码迷,mamicode.com
首页 > 其他好文 > 详细

关于TCP下SOCKET的一些测试

时间:2015-06-15 11:15:14      阅读:124      评论:0      收藏: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); //定义版本号码

::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

 技术分享

可以看到服务器端始终没有调用closesocket120秒之后客户端采取另一个策略,发送RST数据包

关于TCP下SOCKET的一些测试

标签:

原文地址:http://blog.csdn.net/liujiayu2/article/details/46500809

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!