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; 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 }