本文學習相關資料:
C/C++ socket編程教程
環境:vs2015
源碼:本文代碼
windows 如何創建客戶端與服務端通信?
TCP:
服務端
在windows先告訴程序我們要使用哪個版本的winsock,成功調用了它才能繼續下去
#pragma comment (lib,"ws2_32.lib") //連接ws2_32.lib
/*
MAKEWORD(2,2)表示使用2.2版本的
WSA:Windows Socket API
Startup:啟動
*/
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata)
然后是創建一個套接字:
/*
這樣就創建了一個套接字了
PF_INET:表示使用ipv4
SOCK_STREAM:表示使用面向連接的數據傳輸方式
IPROTO_TCP:表示使用TCP協議
*/
SOCKET servSock = SOCKET(PF_INET,SOCK_STREAM, IPPROTO_TCP);
然后創建sockaddr_in,用來將上面socket和ip地址、端口綁定
/*
sockaddr_in 是一個結構體
sin_family:使用了ipv4地址
sin_addr.s_add:要綁定的ip地址
sin_port:要綁定的端口inet_addr():將ip地址從字符串轉為整數,每個32位的ip地址都有一個對應的整數
htons():將整型變量從主機字節順序轉變成網絡字節順序
每臺電腦可能由于系統或配置差異導致字節順序不同,這時大家協商好網絡字節的順序,
在通信前先將自己的字節順序轉成網絡字節順序,再發送;
在接受到信息后再轉回自己的字節順序。*/
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
//servAddr.sin_addr.s_add = inet_addr("127.0.0.1");
//要使用inet_pton需要包括頭文件:WS2tcpip.h
//這里使用inet_pton來填寫IP地址的原因是vs2015整天告訴我說inet_addr不安全
inet_pton(AF_INET,"127.0.0.1", &sockAddr.sin_addr.s_addr); //說明要監聽的ip地址servAddr.sin_port = htons(9000);/*
這里第二個參數是SOCKADDR*類型的,結構和sockaddr_in類似
*///綁定
bind(servSock,(SOCKADDR*)&sockAddr,sizeof(SOCKADDR));
現在將端口和IP地址都綁定好了,可以開始監聽有沒有人要連接這個端口了
/*
第一個參數表示用來監聽的套接字
第二個參數表示隊列長度,來訪問的人都在這個隊列里面,等待接收
*/listen(servSock,20);
現在有客戶端發來連接請求了,要怎么接受連接呢
/*
accept 取出隊列的第一個連接請求
第一個參數:在listen的那個socket
第二個參數:客戶端的IP地址和端口
第三個參數:SOCKADDR的大小*/
int nSize = sizeof(SOCKADDR);
socketaddr_in clnAddr;
SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize)
那現在成功接受請求了,那么要怎么接收發送的數據呢?
/*
recv 接收客戶端發來的數據,默認是阻塞的(也就是程序會一直等到客戶端發信息來,否則不會往下執行)
第一個參數:accept時候返回的套接字
第二個參數:數據保存的地方
第三個參數:讀取數據的最大長度(字節)
返回值:實際讀取了多少個字節的數據
*/
int maxlen = 200;
char buf[maxlen]
int len = recv(clntSock, buf, maxlen, 0)
好了現在服務端接收到關閉的信息了,要怎么關閉呢
/*
記得都要關閉哦
CleanUp:清理
*/
closesocket(clntSock);
closesocket(servSock);
WSACleanup();
客戶端
前面和服務端類似,都是需要創建套接字,說明服務端的IP地址和端口
記得在這前面要說明使用的socket 版本哦
SOCKET client = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(sockaddr_in));
servAddr.sin_family = PF_INET;
//servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
inet_pton(AF_INET,"127.0.0.1", &servAddr.sin_addr.s_addr); //說明要監聽的ip地址
servAddr.sin_port = htons(9000);
然后可以開始連接了
/*
這個和bind函數類似,只不過那個是綁定,這個連接,連接成功是返回0,否則返回-1
*/
connect(client, (sockaddr*)&servAddr, sizeof(sockaddr_in));
好的,現在客戶端連接上了,是時候發送信息過去了
/*
send
第一個參數:連接成功的那個套接字
第二個參數:發送的內容
第三個參數:發送的內容長度
第四個參數:??
*/
send(client,"Hello Server",13,0);
好了,信息發過去了,我這邊也要關閉了
closesocket(client);
WSACleanup();