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