UDPTCP通信实验
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
计算机通信网络实验
UDP/TCP通信实验
学院:
班级:
学号:
姓名:
2012年11月6日
一、实验目的
熟练掌握UDP、TCP Client/Server模式的通信原理
二、实验内容
传输控制协议(Transport Control Protocol)是一种面向连接的,可靠的传输层协议。
面向连接是指一次正常的TCP传输需要通过在TCP客户端和TCP服务端建立特定的虚电路连接来完成,该过程通常被称为“三次握手”。
可靠性可以通过很多种方法来提供保证,在这里我们关心的是数据序列和确认。
TCP通过数据分段(Segment)中的序列号保证所有传输的数据可以在远端按照正常的次序进行重组,而且通过确认保证数据传输的完整性。
要通过TCP传输数据,必须在两端主机之间建立连接。
举例说明,TCP客户端需要和TCP服务端建立连接,过程如图所示:
第一步中,客户端向服务端提出连接请求。
这时TCP SYN标志置位。
客户端告诉服务端序列号区域合法,需要检查。
客户端在TCP报头的序列号区中插入自己的ISN。
服务端收到该TCP分段后,在第二步以自己的ISN回应(SYN标志置位),同时确认收到客户端的第一个TCP分段(ACK标志置位)。
在第三步中,客户端确认收到服务端的ISN(ACK标志置位)。
到此为止建立完整的TCP 连接,开始全双工模式的数据传输过程。
根据以上内容编写一个TCP Client/Server模式的通信程序。
事实上网络程序是由两个部分组成:客户端、服务器端
它们的建立步骤如下:
服务器端
socket-->bind-->listen-->accept
客户端
socket-->connect
三、实验步骤
1.编写UDP、TCP Client/Server模式的通信程序;
2.调试并运行自己编写的实现程序;
3.了解TCP Client/Server模式的工作原理,比较二者的不同,如出现异常情况,在
实验报告中写出原因分析;
4.保留编写的实现程序。
四、实验过程
1.TCP Client/Server模式的通信程序
服务器端操作socket(套接字):
1.在初始化阶段调用WSAStartup()
2、建立Socket
3、绑定端口
4、监听
5、服务器端接受客户端的连接请求
6、发送及接收信息
7、结束socket 连接
相应的程序:
//*********************** server.c ************************
#include<winsock.h> //WINSOCK API的头文件,需要包含在项目中
#pragma comment(lib,"ws2_32.lib") //WINSOCK API连接库文件
#include<stdio.h>
#include<string.h>
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
int len;
char recvBuf[50];
char sendBuf[50];
SOCKET sockSrv; //用于服务器监听的Socket
SOCKADDR_IN addrSrv; //存放服务端套接字信息
SOCKADDR_IN addrClient; //存放连接上的客户端套接字信息
SOCKET new_sock; //用于连接后新的socket
//************************ 初始化阶段*******************
wVersionRequested = MAKEWORD( 1, 1 ); //WinSocket1.1版本
err = WSAStartup( wVersionRequested, &wsaData );
//此函数在应用程序中初始化Windows Sockets DLL ,只有此函数调用成功后,才可以再调用其他Windows Sockets DLL中的API函数
//wsaData用来存储系统传回的关于WinSocket的资料
if ( err != 0 ) { //err=0就表示初始化成功
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
{
WSACleanup( );
return;
}
//************************ 建立socket ********************
sockSrv=socket(AF_INET,SOCK_STREAM,0);
//调用Socket()函数在服务器建立监听的Socket,并定义此Socket所使用的通信协议。
//指定地址描述为AF_INET
//指定socket类型为SOCK_STREAM,建立的是遵从TCP/IP协议的socket
if(sockSrv==-1)return; //错误检查
//************************ 绑定端口*********************
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
//设置服务器地址,INADDR_ANY表示使用自己的IP地址
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000); //设定端口为6000
if(bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR))==-1)return;// 绑定端口并检查
//************************** 监听***********************
if(listen(sockSrv,5)==-1)return;
//使服务器端的Socket进入监听状态,并设定可以建立的最大连接数为5
//********************** 发送及接受消息*****************
len=sizeof(SOCKADDR_IN); //Socket的地址值的长度
while(1)
{
new_sock=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
// 接受客户端连接,获取客户端的ip地址
if(new_sock==-1)continue;
printf("got connection from client:%s\n-------Input \"exit\" to disconnect from client.-------\n",inet_ntoa(addrClient.sin_addr));
// 接受客户端连接,获取客户端的ip地址
printf("Server:");
scanf("%s",sendBuf);
//输入服务器要发送的消息,或者输入exit可断开连接
while(strcmp(sendBuf,"exit")!=0){
send(new_sock,sendBuf,strlen(sendBuf)+1,0);
// 发送消息到客户端
recv(new_sock,recvBuf,50,0);
// 接受客户端消息
if(strcmp(recvBuf,"exit")==0)break;
printf("Client:%s\nServer:",recvBuf);
scanf("%s",sendBuf);
//输入服务器要发送的消息,或者输入exit可断开连接
}
send(new_sock,"exit",5,0);
// 发送消息到客户端
printf("-------The session is terminated!------\n");
closesocket(new_sock);//断开连接
}
}
//********************** end of program ******************
客户端操作socket(套接字):
1.在初始化阶段调用WSAStartup()
2、建立Socket
3、设置服务器地址及端口号
4、连接服务器
5、发送及接收信息
6、结束socket 连接
#include <stdio.h>
#include <Winsock2.h> //WINSOCK API的头文件,需要包含在项目中
#pragma comment(lib, "ws2_32.lib") //WINSOCK API连接库文件
#include <string.h>
void main()
{
WORD wVersionRequested;
WSADATA wsaData; //WSAata用来存储系统传回的关于WinSocket的资料。
int err;
SOCKET sockClient;
SOCKADDR_IN addrSrv;
char recvBuf[50];
char sendBuf[50];
//************************ 初始化阶段*********************
wVersionRequested = MAKEWORD( 1, 1 ); //WinSocket1.1版本
err = WSAStartup( wVersionRequested, &wsaData );
//此函数在应用程序中初始化Windows Sockets DLL ,只有此函数调用成功
后,才可以再调用其他Windows Sockets DLL中的API函数
//wsaData用来存储系统传回的关于WinSocket的资料
if ( err != 0 )return;
if ( LOBYTE( wsaData.wVersion ) != 1 ||HIBYTE( wsaData.wVersion ) != 1 )
{
WSACleanup( );
return;
}
//***************** 建立socket、发送、接受消息*************** sockClient=socket(AF_INET,SOCK_STREAM,0);// AF_INET ..tcp连接
//初始化连接与端口号
addrSrv.sin_addr.S_un.S_addr=inet_addr("222.25.162.196");
//设置服务器地址
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000); // 设置端口号
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
//连接服务器
printf("-------got connection from server.-------\n-------Input \"exit\" to disconnect from server.-------\n");
recv(sockClient,recvBuf,50,0);//接受数据
while(strcmp(recvBuf,"exit")!=0){
printf("Server:%s\nClient:",recvBuf);
scanf("%s",sendBuf); //输入服务器要发送的消息
if(strcmp(sendBuf,"exit")==0){
send(sockClient,"exit",5,0);
break;
}
send(sockClient,sendBuf,strlen(sendBuf)+1,0);//发送数据
recv(sockClient,recvBuf,50,0);//接受数据
}
printf("-------The session is terminated!------\n");
closesocket(sockClient);//关闭连接
WSACleanup();
}
试验过程:
1、在IP地址为:222.25.162.196的主机上打开服务器;
2、在IP地址为:222.25.162.84的主机上打开客户端;
3、在IP地址为:222.25.162.5的主机上也打开客户端;
4、服务器与IP地址为:222.25.162.84的主机进行通信,然后断开连接;
5、服务器与IP地址为:222.25.162.5的主机进行通信,然后断开连接;
IP地址为:222.25.162.196的主机上的截图
IP地址为:222.25.162.84的主机上的截图
IP地址为:222.25.162.5的主机上的截图
分析:
客户端1:IP地址为:222.25.162.84
客户端2:IP地址为:222.25.162.5
从截图上可以看出服务器先与客户端1连接上,建立步骤为:
服务器端
socket-->bind-->listen-->accept
客户端
socket-->connect
当它们通信结束断开连接后,服务器再与客户端2连接进行通信。
这是因为在accept()函数中,当某个客户端试图与服务器监听的端口连接时,该连接请求将排队等待服务器用accept接收它并为其建立一个连接。
当客户端2试图与服务器监听的端口连接时,服务器正在与客户端1通信,因此它排队等候。
当服务器断开与客户端1的连接后,服务器用accept将排队等待的客户端2接收并为其建立一个连接,与其通信。
2.UDP Client/Server模式的通信程序
服务器端操作socket(套接字):
1.在初始化阶段调用WSAStartup()
2、建立Socket
3、绑定端口
4、发送及接收信息
5、结束socket 连接
//*********************** server.c *****************************
#include<winsock.h> //WINSOCK API的头文件,需要包含在项目中
#pragma comment(lib,"ws2_32.lib") //WINSOCK API连接库文件
#include<stdio.h>
#include<string.h>
const int bufferlen=1024; //缓存器大小
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
int len;
int fromlen=sizeof(struct sockaddr);
char recvBuf[bufferlen]; //接受缓存
char sendBuf[bufferlen]; //发送缓存
SOCKET sockSrv; //用于服务器监听的Socket
SOCKADDR_IN addrSrv; //服务端地址
SOCKADDR_IN addrClient; //客户端地址
//************************ 初始化阶段 ***************************
wVersionRequested = MAKEWORD( 1, 1 ); //WinSocket1.1版本
err = WSAStartup( wVersionRequested, &wsaData );
//wsaData用来存储系统传回的关于WinSocket的资料
if ( err != 0 ) { //err=0就表示初始化成功
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup( );
return;
}
//************************ 建立socket **************************
sockSrv=socket(AF_INET,SOCK_DGRAM,0);
//调用Socket()函数在服务器建立监听的Socket,并定义此Socket所使用的通信协议。
//指定socket类型为SOCK_DGRAM,使用不连续不可靠的数据包连接,即UDP协议if(sockSrv==-1)return; //错误检查
//************************ 绑定端口 *****************************
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
//设置服务器地址,INADDR_ANY表示使用自己的IP地址
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000); //设定端口为6000
if(bind(sockSrv,(LPSOCKADDR)&addrSrv,sizeof(SOCKADDR))==-1)return; // 绑定端口并检查
//********************** 发送及接受消息 ************************
len=sizeof(SOCKADDR_IN); //Socket的地址值的长度
memset(recvBuf,0,sizeof(recvBuf)); //初始化接收缓冲区
printf("---------Server waiting.----------\n");
while(1)
{
recvfrom(sockSrv,recvBuf,bufferlen,0,(SOCKADDR*)&addrClient,&fromlen) ;//从客户端接收数据
if(strcmp(recvBuf,"exit")==0){ //如果接受到exit指令,直接continue,等待接受下一个客户端的连接
printf("-------The session with %s is
terminated!------\n\n",inet_ntoa(addrClient.sin_addr));
continue;
}
printf("client-%s:%s\n",inet_ntoa(addrClient.sin_addr),recvBuf);
//输出客户IP地址、端口号和接收到的数据
printf("server:");
scanf("%s",sendBuf); //输入服务器要发送的消息,或者输入exit可断开连接
if(strcmp(sendBuf,"exit")==0){
sendto(sockSrv,"exit",5,0,(SOCKADDR *)&addrClient,len);
printf("-------The session with %s is
terminated!------\n\n",inet_ntoa(addrClient.sin_addr));
continue;
}
sendto(sockSrv,sendBuf,sizeof(sendBuf)+1,0,(SOCKADDR
*)&addrClient,len); //给客户发送信息
printf("\n");
}
closesocket(sockSrv); //关闭连接
WSACleanup();
}
//********************** end of program ************************
客户端操作socket(套接字):
1.在初始化阶段调用WSAStartup()
2、建立Socket
3、设置服务器地址及端口号
4、发送及接收信息
5、结束socket 连接
相应的程序:
//*********************** client.c *****************************
#include <stdio.h>
#include <Winsock2.h> //WINSOCK API的头文件,需要包含在项目中
#pragma comment(lib, "ws2_32.lib") //WINSOCK API连接库文件
#include <string.h>
const int bufferlen=1024;
void main()
{
WORD wVersionRequested;
WSADATA wsaData; //WSAata用来存储系统传回的关于WinSocket的资料。
int err;
int len;
SOCKET sockClient; //用于服务器监听的Socket
SOCKADDR_IN addrSrv; //服务器地址
char recvBuf[bufferlen]; //接受缓存
char sendBuf[bufferlen]; //发送缓存
char serverip[20];
//************************ 初始化阶段 ******************************
wVersionRequested = MAKEWORD( 1, 1 ); //WinSocket1.1版本
err = WSAStartup( wVersionRequested, &wsaData );
//wsaData用来存储系统传回的关于WinSocket的资料
if ( err != 0 )return;
if ( LOBYTE( wsaData.wVersion ) != 1 ||HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup( );
return;
}
//***************** 建立socket、发送、接受消息 ***********************
sockClient=socket(AF_INET,SOCK_DGRAM,0);// AF_INET ..udp连接printf("input server IP:");
scanf("%s",serverip); //输入服务器ip
addrSrv.sin_addr.S_un.S_addr=inet_addr(serverip); //设置服务器地址
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000); // 设置端口号
memset(recvBuf,0,sizeof(recvBuf)); //初始化接收缓冲区
len=sizeof(SOCKADDR_IN); //Socket的地址值的长度
printf("----------------------------------\n");
while(1)
{
printf("client:");
scanf("%s",sendBuf);
//输入服务器要发送的消息,或者输入exit可断开连接
if(strcmp(sendBuf,"exit")==0){
//当客户端要断开连接时,给服务器发送exit,跳出循环
sendto(sockClient,"exit",5,0,(SOCKADDR *)&addrSrv,len);
printf("-------The session is terminated!------\n");
break;
}
sendto(sockClient,sendBuf,sizeof(sendBuf)+1,0,(SOCKADDR
*)&addrSrv,len); //发送消息
recvfrom(sockClient,recvBuf,bufferlen,0,(SOCKADDR *)&addrSrv,&len); //接受来自服务器的消息
if(strcmp(recvBuf,"exit")==0){
//如果收到服务器的exit指令,则跳出循环
printf("-------The session is terminated!------\n");
break;
}
printf("server:%s\n",recvBuf);
}
closesocket(sockClient);//关闭连接
WSACleanup();
}
//********************** end of program ************************试验过程:
1、在IP地址为:222.25.162.196的主机上打开服务器;
2、在IP地址为:222.25.162.84的主机上打开客户端;
3、在IP地址为:222.25.162.5的主机上也打开客户端;
4、服务器同时与IP地址为:222.25.162.84的主机和服务器与IP地址为:
222.25.162.5的主机进行通信,然后断开连接;
IP地址为:222.25.162.196的主机上的截图
IP地址为:222.25.162.84的主机上的截图
IP地址为:222.25.162.5的主机上的截图
分析:
客户端1:IP地址为:222.25.162.84
客户端2:IP地址为:222.25.162.5
从截图上可以看出服务器可以同时接收这两个客户端传来的消息,而且不需要先建立连接,这是UDP与TCP不同的地方。
五、心得体会
在本次UDP/TCP通信实验中,我不仅进一步熟练掌握socket的编程命令,而且在实际的编程中对UDP、TCP Client/Server模式的通信原理有了更深的了解,知道了它们之间的差异,TCPClient/Server模式的通信需要“三次握手”建立连接,然后才能进行通信,而且服务器不能同时与两个客户端进行连接,而UDPClient/Server模式的通信却可以。
虽然在上次的socket编程实验中已经多socket的编程命令有了一定的了解,但是在本次实验中我们还是遇到了不少问题,尤其是在进行UDPClient/Server模式的通信的编程时,以为和TCP的差别不大,就在TCP的程序的基础上进行修改,结果出现了很多意想不到的问题。
但在我们上网查询后都一一得到了解决。
通过本次实验,我解读和编写程序的能力都有了一定的提高,而且和同组的其他同学的合作也让我体会到了团队的力量永远胜过个人,总之,这次实验让我收获匪浅。