风吹过


以前,晚餐后在学校田径场的大榕树下,散散步吹吹风,累了就去图书馆看看书,感觉真好。


windows下的socket网络编程

[TOC] 博客园文章地址 http://www.cnblogs.com/oloroso/archive/2015/07/01/4613296.html

windows下的socket网络编程

已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先写了个简单的winSocket网路通信的例子,以便以后用到的时候有个参考。

windows下使用winsock编程与linux/unix的区别在于windows下需要先有一个初始化的操作,结束的时候需要一个清理的操作。还有windows下编译的时候需要连接ws32_lib库。

大致过程如下

  • 1、初始化

    /加载Winsock DLL/
    WSADATA wsd;
    if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) {
    printf(“Winsock 初始化失败!\n”);
    return 1;
    }

  • 2、socket相关函数调用

    socket(…)
    bind(…)
    listen(…)
    connect(…)
    accept(…)
    send/sendto
    recv/recvfrom

  • 3、清理
    WSACleanup();

clinet.c 客户端

客户端的流程很简单。

  • 1、先是使用socket函数产生一个打开的socket文件描述符。
  • 2、使用connect函数去连接服务端
  • 3、使用read/recv等读文件函数从服务端接收数据,使用write/send等写文件的函数向服务端发送数据

上面是典型的TCP编程流程,如果是UDP的话不需要connect去连接服务端直接使用sendto函数来发送数据,使用recvfrom接收来自服务器的数据

server.c 服务器端

服务器端的流程比客户端稍微复杂一点

  • 1、调用socket打开一个socket句柄
  • 2、调用bind来绑定socket句柄到一个网口的某个端口
  • 3、调用listen来设置(启用)监听
  • 4、调用accept来等待客户端的连接

上面是典型的TCP编程流程,如果是UDP的,那么不需要3,4这两部,直接使用recvfrom来接收客户端发过来的数据即可。

UDP通信的实现

我这里没有写TCP的,因为都是局域网内,就简单的写了个。
这里是在虚拟机里面测试的截图,代码见最后。

 

代码如下

这是TCP的,UDP的就不贴了。

#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>

#pragma comment(lib , “ws2_32.lib”)

#define BUFSIZE 4096 /缓冲区大小/

int main_client(int argc , char *argv[]) { WSADATA wsd; SOCKET sClient; char Buffer[BUFSIZE]; int ret; struct sockaddr_in server; unsigned short port; struct hostent *host = NULL;

</span><span style="color: #0000ff;">if</span> (argc &lt; <span style="color: #800080;">3</span><span style="color: #000000;">) {
    printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">Usage:%s IP Port\n</span><span style="color: #800000;">"</span> , argv[<span style="color: #800080;">0</span><span style="color: #000000;">]);
    </span><span style="color: #0000ff;">return</span> -<span style="color: #800080;">1</span><span style="color: #000000;">;
}


</span><span style="color: #008000;">/*</span><span style="color: #008000;">加载Winsock DLL</span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (WSAStartup(MAKEWORD(<span style="color: #800080;">2</span> , <span style="color: #800080;">2</span>) , &amp;wsd) != <span style="color: #800080;">0</span><span style="color: #000000;">) {
    printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">Winsock    初始化失败!\n</span><span style="color: #800000;">"</span><span style="color: #000000;">);
    </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">1</span><span style="color: #000000;">;
}

</span><span style="color: #008000;">/*</span><span style="color: #008000;">创建Socket</span><span style="color: #008000;">*/</span><span style="color: #000000;">
sClient </span>=<span style="color: #000000;"> socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);
</span><span style="color: #0000ff;">if</span> (sClient ==<span style="color: #000000;"> INVALID_SOCKET) {
    printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">socket() 失败: %d\n</span><span style="color: #800000;">"</span><span style="color: #000000;"> , WSAGetLastError());
    </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">1</span><span style="color: #000000;">;
}
</span><span style="color: #008000;">/*</span><span style="color: #008000;">指定服务器地址</span><span style="color: #008000;">*/</span><span style="color: #000000;">
server.sin_family </span>=<span style="color: #000000;"> AF_INET;
port </span>= atoi(argv[<span style="color: #800080;">2</span><span style="color: #000000;">]);
server.sin_port </span>=<span style="color: #000000;"> htons(port);
server.sin_addr.s_addr </span>= inet_addr(argv[<span style="color: #800080;">1</span><span style="color: #000000;">]);

</span><span style="color: #0000ff;">if</span> (server.sin_addr.s_addr ==<span style="color: #000000;"> INADDR_NONE) {
    host </span>= gethostbyname(argv[<span style="color: #800080;">1</span>]);    <span style="color: #008000;">//</span><span style="color: #008000;">输入的地址可能是域名等</span>
    <span style="color: #0000ff;">if</span> (host ==<span style="color: #000000;"> NULL) {
        printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">无法解析服务端地址: %s\n</span><span style="color: #800000;">"</span> , argv[<span style="color: #800080;">1</span><span style="color: #000000;">]);
        </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">1</span><span style="color: #000000;">;
    }
    CopyMemory(</span>&amp;<span style="color: #000000;">server.sin_addr ,
                host</span>-&gt;h_addr_list[<span style="color: #800080;">0</span><span style="color: #000000;">] ,
                host</span>-&gt;<span style="color: #000000;">h_length);
}
</span><span style="color: #008000;">/*</span><span style="color: #008000;">与服务器建立连接</span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (connect(sClient , (<span style="color: #0000ff;">struct</span> sockaddr*)&amp;<span style="color: #000000;">server ,
                </span><span style="color: #0000ff;">sizeof</span>(server)) ==<span style="color: #000000;"> SOCKET_ERROR) {
    printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">connect() 失败: %d\n</span><span style="color: #800000;">"</span><span style="color: #000000;"> , WSAGetLastError());
    </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">1</span><span style="color: #000000;">;
}

</span><span style="color: #008000;">/*</span><span style="color: #008000;">发送、接收消息</span><span style="color: #008000;">*/</span>

<span style="color: #0000ff;">for</span><span style="color: #000000;"> (;;) {
    </span><span style="color: #008000;">//</span><span style="color: #008000;">从标准输入读取要发送的数据
    </span><span style="color: #008000;">//</span><span style="color: #008000;">gets_s(Buffer,BUFSIZE);</span>

gets(Buffer); //向服务器发送消息 ret = send(sClient , Buffer , strlen(Buffer) , 0); if (ret == 0) { break; } else if (ret == SOCKET_ERROR) { printf(send() 失败: %d\n , WSAGetLastError()); break; } printf(Send %d bytes\n , ret); //接收从服务器来的消息 ret = recv(sClient , Buffer , BUFSIZE , 0); if (ret == 0) { break; } else if (ret == SOCKET_ERROR) { printf(recv() 失败: %d\n , WSAGetLastError()); break; } Buffer[ret] = \0; printf(Recv %d bytes:\n\t%s\n , ret , Buffer);

}
</span><span style="color: #008000;">//</span><span style="color: #008000;">用完了,关闭socket句柄(文件描述符)</span>

closesocket(sClient); WSACleanup(); //清理 return 0; }

查看 clinet.c 代码
  1 #include <winsock2.h>
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4
  5 #pragma comment(lib , “ws2_32.lib”)
  6
  7
  8 #define DEFAULT_BUFFER 4096 /缓冲区大小/
  9
 10
 11 /与客户机通信的线程函数/
 12 DWORD WINAPI ClientThread(LPVOID lpParam)
 13 {
 14     SOCKET sock = (SOCKET)lpParam;
 15     char Buffer[DEFAULT_BUFFER];
 16     int ret , nLeft , idx;
 17     while (1) {
 18         /接收来自客户机的消息/
 19         ret = recv(sock , Buffer , DEFAULT_BUFFER , 0);
 20         if (ret == 0)
 21             break;
 22         else if (ret == SOCKET_ERROR) {
 23             printf(recv() 失败: %d\n , WSAGetLastError());
 24             break;
 25         }
 26         Buffer[ret] = \0;
 27         printf(Recv: %s\n , Buffer);    //打印接收到的消息
 28
 29
 30         nLeft = ret;
 31         idx = 0;
 32         while (nLeft > 0) {
 33             /向客户机发送回应消息/
 34             ret = send(sock , &Buffer[idx] , nLeft , 0);
 35             if (ret == 0)
 36                 break;
 37             else if (ret == SOCKET_ERROR) {
 38                 printf(send() 失败: %d\n , WSAGetLastError());
 39                 break;
 40             }
 41             nLeft -= ret;
 42             idx += ret;
 43         }
 44     }
 45     return 0;
 46 }
 47
 48 int main_server(int argc , char argv)
 49 {
 50     WSADATA        wsd;
 51     HANDLE        hThread;
 52     DWORD        dwThread;
 53     SOCKET        sListen , sClient;
 54     int            AddrSize;
 55     unsigned short port;
 56     struct sockaddr_in local , client;
 57
 58     if (argc < 2) {
 59         printf(Usage:%s Port\n , argv[0]);
 60         return -1;
 61     }
 62
 63     /加载Winsock DLL/
 64     if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) {
 65         printf(WinSock 初始化失败!\n);
 66         return 1;
 67     }
 68
 69     /创建Socket/
 70     sListen = socket(AF_INET , SOCK_STREAM , IPPROTO_IP);
 71     if (sListen == SOCKET_ERROR) {
 72         printf(socket() 失败: %d\n , WSAGetLastError());
 73         return 1;
 74     }
 75
 76     local.sin_family = AF_INET;
 77     local.sin_addr.s_addr = htonl(INADDR_ANY);
 78     port = atoi(argv[1]);    //获取端口值
 79     local.sin_port = htons(port);
 80
 81     /绑定Socket/
 82     if (bind(sListen ,
 83         (struct sockaddr)&local ,
 84         sizeof(local)) == SOCKET_ERROR) {
 85         printf(bind() 失败: %d\n , WSAGetLastError());
 86         return 1;
 87     }
 88     /打开监听/
 89     listen(sListen , 8);
 90
 91     /在端口进行监听,一旦有客户机发起连接请示
 92     就建立与客户机进行通信的线程/
 93     while (1) {
 94         AddrSize = sizeof(client);
 95         /监听是否有连接请求/
 96         sClient = accept(sListen ,
 97                          (struct sockaddr)&client ,
 98                          &AddrSize);
 99         if (sClient == INVALID_SOCKET) {
100             printf(accept() 失败: %d\n , WSAGetLastError());
101             break;
102         }
103         printf(接受客户端连接: %s:%d\n ,
104                inet_ntoa(client.sin_addr) ,
105                ntohs(client.sin_port));
106
107         //创建一个线程去处理
108         hThread = CreateThread(NULL , 0 , ClientThread ,
109                                (LPVOID)sClient , 0 , &dwThread);
110
111         if (hThread == NULL) {
112             printf(CreateThread() 失败: %d\n , GetLastError());
113             break;
114         }
115         //处理完后关闭
116         CloseHandle(hThread);
117     }
118     closesocket(sListen);
119     WSACleanup();    //用完了要清理
120     return 0;
121 }
查看 server.c 代码

测试代码(main)

 1 extern int main_client(int , char);
 2 extern int main_server(int , char);
 3
 4 int main(int c , char v)
 5 {
 6     if (c == 3) {
 7         main_client(c , v);
 8     }
 9     else {
10         main_server(c , v);
11     }
12     return 0;
13
14 }
查看 test 代码