关于TCP下SOCKET的一些测试
=============================測試代碼===========================
客戶端:
#include<winsock2.h> //包含頭文件 #include<stdio.h> #include<windows.h> #pragma comment(lib,"WS2_32.lib") //顯式連接套接字庫int main() //主函數開始 {WSADATA data; //定義WSADATA結構體對象WORD w=MAKEWORD(2,0); //定義版本號碼::WSAStartup(w,&data); //初始化套接字庫SOCKET s; //定義連接套接字句柄char sztext[20]={0};s=::socket(AF_INET,SOCK_STREAM,0); //創建TCP套接字sockaddr_in addr; //定義套接字地址結構addr.sin_family=AF_INET; //初始化地址結構addr.sin_port=htons(75);addr.sin_addr.S_un.S_addr=inet_addr("192.168.0.20");printf("客戶端已經啟動\r\n"); //輸出提示信息int ret_con = ::connect(s,(sockaddr*)&addr,sizeof(addr));Sleep(100000);char t[200]="12345";int r = ::send(s,t,0,0);Sleep(1000);::closesocket(s); //關閉套接字句柄char buf[100]={0};int r2 = ::recv(s,buf,100,0);printf("%s",buf);::WSACleanup(); //釋放套接字庫if(getchar()) //如果有輸入,則關閉程序{return 0; //正常結束程序}else{::Sleep(100); //程序睡眠}return 0; }?
服務器:
#include<winsock2.h> //包含頭文件 #include<stdio.h> #include<windows.h> #pragma comment(lib,"WS2_32.lib") //顯式連接套接字庫int main() //主函數開始 {WSADATA data; //定義WSADATA結構體對象WORD w=MAKEWORD(2,0); //定義版本號碼char sztext[]="你已經連接上"; //定義并初始化發送到客戶端的字符數組::WSAStartup(w,&data); //初始化套接字庫SOCKET s,s1; //定義連接套接字和數據收發套接字句柄s=::socket(AF_INET,SOCK_STREAM,0); //創建TCP套接字sockaddr_in addr,addr2; //定義套接字地址結構int n=sizeof(addr2); //獲取套接字地址結構大小addr.sin_family=AF_INET; //初始化地址結構addr.sin_port=htons(75);addr.sin_addr.S_un.S_addr=INADDR_ANY;::bind(s,(sockaddr*)&addr,sizeof(addr)); //綁定套接字::listen(s,5); //監聽套接字printf("服務器已經啟動\r\n"); //輸出提示信息while(true){s1=::accept(s,(sockaddr*)&addr2,&n); //接受連接請求,正常情況下此函數是個阻塞函數,如果沒有阻塞則是此函數運行失敗if(s1!=NULL){printf("%s已經連接上\r\n",inet_ntoa(addr2.sin_addr));//::send(s1,sztext,sizeof(sztext),0); //向客戶端發送字符數組}char buf[100]="";::recv(s1,buf,100,0);printf("%s",buf);Sleep(4*1000);char t[200]="12345";int r = ::send(s1,t,5,0);printf("\n%d\n",r);Sleep(10*1000);::closesocket(s1);Sleep(500*60*1000);::closesocket(s); //關閉套接字句柄::WSACleanup(); //釋放套接字庫if(getchar()) //如果有輸入,則關閉程序{return 0; //正常結束程序}else{::Sleep(100); //應用睡眠0.1秒}} }======================================================================
測試環境:
本機:??????WIN7?????192.168.0.20
虛擬機:????WINXP???192.168.0.250
抓包工具:??Wireshark
?
測試內容:
1.客戶端連接IP地址不存在或者端口沒有開放
?IP不存在時Wireshark抓不到數據包
使用下面的代碼測試connect返回時間
int?t1?=?clock();
int?ret_con?=?::connect(s,(sockaddr*)&addr,sizeof(addr));
int?t2?=?clock()?-?t1;
測試結果是20秒
端口不存在時,可以抓到6個數據包
客戶端嘗試連接3次失敗之后不再嘗試連接
Connect函數返回時間是1秒
?
2.正常三次握手的抓包情況
成功抓到三次握手數據包。Connect返回時間為0
?
3.研究三次握手與accept函數有無關系
研究方法,服務器accept函數上面下斷點,單步走,查看抓包情況
accept函數還沒有調用已經抓到數據包,實驗證明三次握手與accept函數無關
?
4.客戶端簡單發送一個數據包
服務器代碼:(connect函數之后就一直sleep)
s1=::accept(s,(sockaddr*)&addr2,&n); //接受連接請求,正常情況下此函數是個阻塞函數,如果沒有阻塞則是此函數運行失敗
if(s1!=NULL)
{
printf("%s已經連接上\r\n",inet_ntoa(addr2.sin_addr));
}
Sleep(1000?*?1000);
一共五條數據,前三條是3次握手,第四條是send發送”12345”的這條數據包,第5條是服務器響應數據包,表示自己已經收到數據了。測試過程中服務器并沒來得及調用recv函數,說明TCP協議把數據先接收到了某個緩沖區,等待應用程序來讀取。
?
5.客戶端send發送數據為0的情況
服務器代碼:
s1=::accept(s,(sockaddr*)&addr2,&n); //接受連接請求,正常情況下此函數是個阻塞函數,如果沒有阻塞則是此函數運行失敗
if(s1!=NULL)
{
printf("%s已經連接上\r\n",inet_ntoa(addr2.sin_addr));
}
char?buf[100]="";
::recv(s1,buf,100,0);
printf("接收到的數據為:%s",buf);
Sleep(400*1000);
客戶端代碼:
char?t[200]="12345";
int?r?=?::send(s,t,0,0);
?
客戶端方面沒有抓到發送出去的數據包,只有握手數據包
服務器方面也沒有收到數據包
調用closesocket函數之后客戶端給服務發送了一個數據包,服務器發送了響應數據包
由于接收到客戶端的closesocket函數,服務器的recv函數立即返回。
?
6.客戶端send函數之后立即調用closesocket函數
直接運行:
可以看到:服務器方面沒有響應客戶端的send函數(發送相應的ACK數據包)而是直接響應了closesocket數據包。
但不運行:
數據包正常,分析原因應該是TCP的規定,接收到closesocket函數之后不再響應send的數據包
7.客戶端連續調用send函數
服務器是否調用recv進行接受,客戶端連續發送的數據會分兩撥到達
服務器接受緩沖區夠大的情況下
8.抓取四次握手釋放連接數據包
服務器代碼:
s1=::accept(s,(sockaddr*)&addr2,&n); //接受連接請求,正常情況下此函數是個阻塞函數,如果沒有阻塞則是此函數運行失敗
if(s1!=NULL)
{
printf("%s已經連接上\r\n",inet_ntoa(addr2.sin_addr));
}
?
Sleep(2*1000);
?
::closesocket(s1);
客戶端代碼:
int?ret_con?=?::connect(s,(sockaddr*)&addr,sizeof(addr));
?
Sleep(1*1000);
::closesocket(s); //關閉套接字句柄
Sleep(100*1000);
要想抓到四次握手數據包必須一方先close函數,另一方緊接著close函數才可以
?
9.客戶端closesocket之后服務器端一直sleep(不發送相應closesocket)
可以看到服務器端始終沒有調用closesocket,120秒之后客戶端采取另一個策略,發送RST數據包
10.測試TCP接收緩沖區
測試方法:客戶端不停地發送數據,但是服務器始終不recv.
char buf[10] = "123456789";
for (int i=0;i<10000;i++)
{
int r = ::send(s,buf,10,0);
if (r != 10 || WSAGetLastError() != 0)
{
printf("---------------erro---------------\n");
}
}
printf("發送完成\n");
可以看到send函數阻塞了,不能發送數據了(底層TCP協議的控制)
總結
以上是生活随笔為你收集整理的关于TCP下SOCKET的一些测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCP/IP TIME_WAIT状态原理
- 下一篇: 一些学习cocos2d的网站