標籤:.com 伺服器端 圖片 inet_ntoa 資料 cte 檔案傳輸 技術分享 winsock
編譯環境:DEV C++配置編譯器
Windows 下 實現 Socket 編譯需要 ws2_32.lib 這個庫的支撐,所以我們編譯前應該配置下編譯器,具體配置步驟如下:
Tools -> Compiler Options
加入 -l 連結,:
實現的功能
伺服器端與用戶端可以互相自由給對方發送訊息,無需在意接收與發送的順序(利用線程實現)!可以實現加法運算。如需其它的功能,可以自行補充,如:實現四則運算、檔案傳輸等。
伺服器程式
/* Name: TCP Server Copyright: -lws2_32 Author: Lance# Date: 18/05/18 Description: TCP Server */#include <stdio.h> #include <winsock2.h> #include <windows.h>#include <string.h>#define PORT 8080 #define BUFSIZE 1024/* 用戶端Socket與發送緩衝 */SOCKET client;unsigned char SendBuf[BUFSIZE+1];enum{ NoConnection, Connected,}LinkStatus;/* 用戶端串連狀態監控線程 */DWORD WINAPI print_message(LPVOID arg){ while(1){ if(!LinkStatus){ printf(" 等待用戶端串連 .... \r\n"); sleep(1); } }}/* 伺服器發送訊息線程 */DWORD WINAPI send_message(LPVOID arg){ while(1){ memset(SendBuf, 0, 1024); fgets(SendBuf, 1024, stdin); send(client, SendBuf, 1024, 0); }} int main(int argc, char* argv[]){ WSADATA wsaData; struct sockaddr_in sin_addr; struct sockaddr_in remoteAddr; unsigned char recvData[BUFSIZE+1]; int nAddrlen = sizeof(remoteAddr); unsigned int num_l, num_r; unsigned char sum_buf[100] = {0}; /* 線程標識 */ HANDLE pthread; /* 啟動 WSA */ WORD sockVersion = MAKEWORD(2, 2); if (WSAStartup(sockVersion, &wsaData)){ perror("WSA boot failed!"); return -1; } /* 建立服務端通訊端 */ SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server == INVALID_SOCKET){ perror("socket error!"); return -1; } /* 配置 sin_addr */ sin_addr.sin_family = AF_INET; sin_addr.sin_port = htons(PORT); /* 可監聽任意的地址 */ sin_addr.sin_addr.S_un.S_addr = INADDR_ANY; /* 監聽指定的地址 */// sin_addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.149"); /* 綁定 */ if (bind(server, (LPSOCKADDR)&sin_addr, sizeof(sin_addr)) == SOCKET_ERROR){ perror("bind error!"); return -1; } /* 監聽 */ if (listen(server, 100) == SOCKET_ERROR){ perror("listen error!"); return -1; } puts("伺服器成功啟動"); /* 建立狀態線程 */ CreateThread(NULL,0,print_message,NULL,0,NULL); /* 建立訊息線程 */ pthread = CreateThread(NULL,0,send_message,NULL,0,NULL); while (1) { LinkStatus = NoConnection; client = accept(server, (SOCKADDR *)&remoteAddr, &nAddrlen); LinkStatus = Connected; if (client == INVALID_SOCKET) { perror("accept error!"); continue; } printf("用戶端:%s 已串連\r\n", inet_ntoa(remoteAddr.sin_addr)); while(1){ /* 資料接收 */ memset(recvData, 0, sizeof(recvData)); int ret = recv(client, recvData, 1024, 0); if (ret > 0){ printf("Recv: %s", recvData); /* 實現加法運算,用戶端發來 "%d + %d =" 形式的資料後,將結果返回至用戶端 */ if(sscanf(recvData, "%d + %d =", &num_l, &num_r) == 2){ sprintf(sum_buf, "%d + %d ,sum is %d", num_l, num_r, num_l + num_r); send(client, sum_buf, sizeof(sum_buf), 0); memset(sum_buf, 0, sizeof(sum_buf)); } }else /* 用戶端異常則斷開當前串連 */ goto Reconnect; /* 用戶端要求退出的話則斷開當前串連 */ if(!strncmp(recvData, "quit", 4)) goto Reconnect; } Reconnect: closesocket(client); puts("*** 用戶端已斷開"); } /* 關閉伺服器通訊端 */ closesocket(server); WSACleanup(); return 0;}
用戶端程式
/* Name: TCP Client Copyright: -lws2_32 Author: Lance# Date: 18/05/18 Description: TCP Client*/#include <stdio.h> #include <winsock2.h> #include <Windows.h> #include <string.h> #define PORT 8080 #define BUFSIZE 1024unsigned char recvData[BUFSIZE+1] = {0}; /* 線程標識 */HANDLE pthread;DWORD WINAPI recv_message(LPVOID arg){ int res; while(1){ memset(recvData, 0, 1024); res = recv((SOCKET)arg, recvData, 1024, 0); if(res > 0) printf("Recv: %s", recvData); else{ printf("*** 伺服器已退出(斷行符號退出程式)"); return 0; } }} int main(int argc, char * argv[]) { unsigned char SendBuf[BUFSIZE+1] = {0}; WSADATA wsaData; SOCKADDR_IN addrServ; if(argc != 2){ puts("argc error"); puts("Usage: <client.exe> <ip addr>"); return -1; } /* 啟動 WSA */ WORD sockVersion = MAKEWORD(2, 2); if (WSAStartup(sockVersion, &wsaData)){ perror("WSA boot failed!"); return -1; } /* 建立 socket */ SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (client == INVALID_SOCKET){ perror("socket failed"); return -1; } /* 配置 socket */ addrServ.sin_family = AF_INET; addrServ.sin_port = htons(PORT); /* 設定管理員 IP */ addrServ.sin_addr.S_un.S_addr = inet_addr(argv[1]); /* 串連至伺服器 */ int ret = connect(client,(SOCKADDR*)&addrServ,sizeof(SOCKADDR)); if (SOCKET_ERROR == ret){ perror("socket connect failed"); closesocket(client); WSACleanup(); return -1; } /* 建立背景工作執行緒 */ pthread = CreateThread(NULL,0 ,recv_message,(LPVOID)client,0,NULL); puts("用戶端成功啟動,輸入'quit'關閉用戶端"); while(1) { memset(SendBuf,0,sizeof(SendBuf)); fgets(SendBuf, 1024, stdin); ret = send(client, SendBuf, 1024, 0); if (SOCKET_ERROR == ret){ closesocket(client); exit(0); } /* 用戶端退出 */ if(!strncmp(SendBuf, "quit", 4)) goto Disconnect; }Disconnect: closesocket(client); WSACleanup(); return 0; }
運行結果示範
開啟 CMD,進入可執行檔所在目錄
執行 server.exe 運行伺服器;
啟動另一個 CMD,執行 client.exe 127.0.0.1 運行用戶端。
雙方可進行通訊,效果
完美實現 Windows 下網路通訊