標籤:ip add Edito image order ica .lib 地址 產生 soc
記初次接觸socket編程,在devC++使用Winsock進行socket編程的一個過程,通過在devC++建立2個項目分別是server、client程式項目,感受通過socket使client與server的一次通訊。
1.建立項目與往常不同,不單單是需要建立一個C檔案,更是要在串連庫中添加 libws2_32在專案管理中的屬性配置串連庫,然後在項目中建立server.c
連線導向的C/S程式工作流程(TCP)
- 使用WSAStartup()函數檢查系統協議棧安裝情況
- 使用socket()函數建立伺服器端通訊通訊端
- 使用bind()函數將建立的通訊端與伺服器位址綁定
- 使用listen()函數使伺服器通訊端做好接收串連請求準備
- 使用accept()接收來自用戶端由connect()函數發出的串連請
- 根據串連請求建立串連後,使用send()函數發送資料,或者使用recv()函數接收資料
- 使用closesocket()函數關閉通訊端(可以先用shutdown()函數先關閉讀寫通道)
- 最後調用WSACleanup()函數結束Winsock Sockets API
server代碼:
#pragma comment(lib,"ws2_32.lib")#include <Winsock2.h>#include <stdio.h>#include <stdlib.h>#define DEFAULT_PORT 5050 //服務端預設連接埠int main(int argc, char* argv[]){int iPort = DEFAULT_PORT;WSADATA wsaData;SOCKET sListen,sAccept;int iLen; //客戶機地址長度int iSend; //發送資料長度char buf[] = "I am a server"; //要發送給客戶的資訊struct sockaddr_in ser,cli; //伺服器和客戶的地址if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){printf("Failed to load Winsock.\n"); //Winsock 初始化錯誤return -1;}sListen = socket(AF_INET,SOCK_STREAM,0); //建立伺服器端通訊端if(sListen == INVALID_SOCKET){printf("socket() Failed: %d\n",WSAGetLastError());return -1;}//以下初始化伺服器端地址ser.sin_family = AF_INET; //使用 IP 位址族ser.sin_port = htons(iPort); //主機序連接埠號碼轉換為網路位元組序連接埠號碼ser.sin_addr.s_addr = htonl(INADDR_ANY); //主機序 IP 位址轉換為網路位元組序主機地址//使用系統指定的 IP 位址 INADDR_ANYif(bind(sListen,(LPSOCKADDR)&ser,sizeof(ser)) == SOCKET_ERROR) //套接定與地址的綁定{printf("bind() Failed: %d\n",WSAGetLastError());return -1;}if(listen(sListen,5) == SOCKET_ERROR) //進入監聽狀態{printf("lisiten() Failed: %d\n",WSAGetLastError());return -1;}iLen = sizeof(cli); //初始化用戶端地址長度參數while(1) //進入迴圈等待客戶的串連請求{sAccept = accept(sListen,(struct sockaddr *)&cli,&iLen);if(sAccept == INVALID_SOCKET){printf("accept() Failed: %d\n",WSAGetLastError());return -1;}printf("Accepted client IP:[%s],port:[%d]\n",inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));//輸出用戶端 IP 位址和連接埠號碼iSend = send(sAccept,buf,sizeof(buf),0); //給用戶端發送資訊if(iSend == SOCKET_ERROR) //錯誤處理{printf("send() Failed: %d\n",WSAGetLastError());break;}else if(iSend == 0){break;}else{printf("send() byte: %d\n",iSend); //輸出發送成功位元組數}closesocket(sAccept);}closesocket(sListen); //關閉 socketWSACleanup(); //輸出發送成功位元組數return 0;}2.儲存最後構建並運行這個項目,編譯產生 server.exe。server項目結構:3.以同樣的方法建立 client 工程,編譯產生 client.exe。
連線導向的C/S程式工作流程(TCP)
- 使用WSAStartup()函數檢查系統協議棧安裝情況
- 使用socket()函數建立用戶端通訊端
- 使用connect()函數發出也伺服器建立串連的請求(調用前可以不用bind()連接埠號碼,由系統自動完成)
- 串連建立後使用send()函數發送資料,或使用recv()函數接收資料
- 使用closesocet()函數關閉通訊端
- 最後調用WSACleanup()函數,結束Winsock Sockets API
client代碼:
#pragma comment(lib,"ws2_32.lib")#include <Winsock2.h>#include <stdio.h>#include <stdlib.h>#define DATA_BUFFER 1024 //預設緩衝區大小int main(int argc, char * argv[]){WSADATA wsaData;SOCKET sClient;int iPort = 5050;int iLen; //從伺服器端接收的資料長度char buf[DATA_BUFFER]; //接收緩衝區struct sockaddr_in ser; //伺服器端地址if(argc<2) //判斷參數輸入是否正確:client [Server IP]{printf("Usage: client [server IP address]\n"); //命令列提示return -1;}memset(buf,0,sizeof(buf)); //初始化接收緩衝區if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){printf("Failed to load Winsock.\n"); //Winsock 初始化錯誤return -1;}ser.sin_family = AF_INET; //初始化伺服器位址資訊ser.sin_port = htons(iPort); //連接埠轉換為網路位元組序ser.sin_addr.s_addr = inet_addr(argv[1]); //IP 位址轉換為網路位元組序sClient = socket(AF_INET,SOCK_STREAM,0); //建立用戶端流式通訊端if(sClient == INVALID_SOCKET){printf("socket() Failed: %d\n",WSAGetLastError());return -1;}//請求與伺服器端建立 TCP 串連if(connect(sClient,(struct sockaddr *)&ser,sizeof(ser)) == INVALID_SOCKET){printf("connect() Failed: %d\n",WSAGetLastError());return -1;}else{iLen = recv(sClient,buf,sizeof(buf),0); //從伺服器端接收資料if(iLen == 0)return -1;else if(iLen == SOCKET_ERROR){printf("recv() Failed: %d\n",WSAGetLastError());return -1;}elseprintf("recv() data from server: %s\n",buf); // 輸出接收資料}closesocket(sClient); //關閉 socketWSACleanup();return 0;}4.運行結果:啟動 server.exe,最後啟動 client.ex 程式與伺服器通訊(用戶端每次串連,會收到來自服務端的訊息,服務端這邊對每次到來的訪問將列印訪問ip和連接埠)
記Windows下初次使用dev C++進行socket編程過程