已经很久没有在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();
客户端的流程很简单。
socket
函数产生一个打开的socket
文件描述符。connect
函数去连接服务端read/send
等读文件函数从服务端接收数据,使用write/recv
等写文件的函数向服务端发送数据上面是典型的TCP
编程流程,如果是UDP
的话不需要connect
去连接服务端直接使用sendto
函数来发送数据,使用recvfrom接收来自服务器的数据
服务器端的流程比客户端稍微复杂一点
socket
打开一个socket句柄bind
来绑定socket句柄到一个网口的某个端口listen
来设置(启用)监听accept
来等待客户端的连接上面是典型的TCP
编程流程,如果是UDP
的,那么不需要3,4
这两部,直接使用recvfrom
来接收客户端发过来的数据即可。
我这里没有写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; if (argc < 3) { printf("Usage:%s IP Port\n" , argv[0]); return -1; } /*加载Winsock DLL*/ if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) { printf("Winsock 初始化失败!\n"); return 1; } /*创建Socket*/ sClient = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP); if (sClient == INVALID_SOCKET) { printf("socket() 失败: %d\n" , WSAGetLastError()); return 1; } /*指定服务器地址*/ server.sin_family = AF_INET; port = atoi(argv[2]); server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr(argv[1]); if (server.sin_addr.s_addr == INADDR_NONE) { host = gethostbyname(argv[1]); //输入的地址可能是域名等 if (host == NULL) { printf("无法解析服务端地址: %s\n" , argv[1]); return 1; } CopyMemory(&server.sin_addr , host->h_addr_list[0] , host->h_length); } /*与服务器建立连接*/ if (connect(sClient , (struct sockaddr*)&server , sizeof(server)) == SOCKET_ERROR) { printf("connect() 失败: %d\n" , WSAGetLastError()); return 1; } /*发送、接收消息*/ for (;;) { //从标准输入读取要发送的数据 //gets_s(Buffer,BUFSIZE); 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); } //用完了,关闭socket句柄(文件描述符) closesocket(sClient); WSACleanup(); //清理 return 0; }
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 }
测试代码(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 }