计算机网络实验报告2.docx
《计算机网络实验报告2.docx》由会员分享,可在线阅读,更多相关《计算机网络实验报告2.docx(22页珍藏版)》请在冰豆网上搜索。
计算机网络实验报告2
《计算机网络》课程实验报告
实验二:
Socket通信编程
姓名
院系
计算机学院
学号
任课教师
钱权,张瑞,袁世忠
指导教师
张瑞
实验地点
计605
实验时间
周五5-6节
实验课表现
出勤、表现得分(10)
实验报告
得分(40)
实验总分
操作结果得分(50)
实验目的:
1.掌握Socket编程过程;
2.编写简单的网络应用程序。
实验内容:
利用你选择的任何一个编程语言,分别基于TCP和UDP编写一个简单的Client/Server网络应用程序。
具体程序要求参见《实验指导书》。
要求以附件形式给出:
●系统概述:
运行环境、编译、使用方法、实现环境、程序文件列表等;
●主要数据结构;
●主要算法描述;
●用户使用手册;
●程序源代码;
实验要求:
(学生对预习要求的回答)(10分)
得分:
●Socket编程客户端的主要步骤
1、用socket()函数创建socket
2、设置目标服务器的IP地址和端口号
3、用connect()函数,与目标服务器连接
4、用Send()函数发送数据,recv()函数接收数据
5、关闭socket
●Socket编程服务器端的主要步骤
1、用socket()函数创建socket
2、用Bind()函数将socket与本机上的一个端口相关联
3、用Listen()函数使socket处于监听模式
4、用accept()函数让服务器接收客户的连接请求
5、用Send()函数发送数据,recv()函数接收数据
6、关闭socket
实验过程中遇到的问题如何解决的?
(10分)
得分:
问题1:
设置IP地址时,刚开始设置成自己的本机的IP地址,但是将程序放到另一台电脑上时就需要修改IP地址。
后来将IP地址设置成127.0.0.1就解决了这一问题。
127.0.0.1是回送地址,指本地机,这样就不用改变本机地址了。
问题2:
做完基于TCP的Client/Server编程后,在做基于UDP的编程的时候,以为在TCP的基础上,只要去掉连接服务器、监听、接受连接请求这些步骤就可以,结果无法实现自己想要的效果。
后来发现UDP还有一些地方与TCP的不同,比如发送、接收数据的函数是sendto()、
recvfrom(),而不是send()、recv(),仔细查看课UDP的相关资料后也就实现了这一程序。
本次实验的体会(结论)(10分)
得分:
这次SOCKET编程一开始觉得无从下手,在网上找了好多资料才了解了socket的用法,仔细研究了之后发现只要掌握了客户端和服务端各自的运行规律,编写程序意外的简单。
通过这次实验我明白了看问题一定要看本质,不能被看似很难的问题吓到。
我一定会再接再厉,争取做好每一次实验。
思考题:
(10分)
思考题1:
(4分)
得分:
你所用的编程语言在Socket通信中用到的主要类及其主要作用。
1.socket类:
用于服务器端程序和客户端程序,实现双方的数据通信。
2.SOCKADDR_IN结构:
记录端口地址、IP地址、协议族等信息。
思考题2:
(6分)
得分:
说明TCP和UDP编程的主要差异和特点。
TCP和UDP是Socket的两种主要操作方式:
面向连接的和无连接的。
无连接的操作使用UDP数据报协议,这个操作不需要连接一个目的的socket,它只是简单地投出数据报,快速高效,但缺少数据安全性。
而面向连接的操作使用TCP协议,一个这个模式的socket必须在发送数据之前与目的地的socket取得一个连接,一旦连接建立了,socket就可以使用一个流接口:
打开-读-写-关闭,所有的发送的信息都会在另一端以同样的顺序被接收,面向连接的操作比无连接的操作效率要低,但数据的安全性更高。
基于TCP的socket编程是采用的流式套接字(SOCK_STREAM)。
基于UDP采用的数据报套接字(SOCK_DGRAM).流式套接字的设计是针对面向连接的网络应用,在数据传输之前需要预先建立连接,在数据传输过程中需要维持连接,在数据传输结束后需要释放连接。
由于采用校验和、确认与超时等差错控制手段,因此流式套接字可以保证数据传输的正确性。
数据报套接字(SOCK_DGRAM)提供无连接的、不可靠的数据传输服务,实际上它是基于TCP/IP协议族中的UDP协议实现的。
数据报套接字提供无序、有差错与有重复的数据流服务。
数据报套接字的设计是针对无连接的网络应用,在数据传输之前不需要预先建立连接。
由于只采用很有限的差错控制手段,因此数据报套接字无法保证数据传输的正确性。
所以TCP面向连接,安全可靠,而UDP面向数据,数据可能会丢失,但是高效,结构简单,网络开销小。
指导教师评语:
日期:
附件:
(一)系统概述
1.运行环境:
windowXP、win7等操作系统
2.编译:
已编译完成,可直接执行可执行文件
3.实现环境:
VisualStudio2010
4.使用方法:
一般窗口应用程序,双击即可运行。
(用户名:
aaa密码:
123)
(二)主要数据结构
服务器端程序:
1.ClassCClientNet{
public:
//连接上指定服务器
intConnect(intport,constchar*address);
//发送信息
//intSendMsg(constchar*msg,intlen);
voidSendMsg();
//关闭
VoidClose();
private:
SOCKETm_sock;
}
2.SOCKET
3.WSAData
4.sockaddr_in
客户端程序:
1.classCServerNet
{
public:
//初始化服务器,返回0表示成功
intInit(constchar*address,intport);
//更新数据
voidRun();
private:
SOCKETm_sock;
}
2.SOCKET
3.WSAData
4.sockaddr_in
(三)用户使用手册
1.运行服务器端程序server.exe。
2.运行客户端程序client.exe。
3.用户登录:
在客户端界面中出现connect则说明可以与服务器连接。
在login:
后输入用户名(aaa),若用户名存在则client端返回该用户名的密码(123),与输入密码比对,若相同则连接成功,可以开始发送消息。
4.发送消息:
在步骤3后,用户端界面会出现“sendyourmessage:
”的提示,此时可以输入想要发送的消息,输完后按enter键发送。
若发送成功,则server界面出现发送的消息,client界面提示“sendsuccessfully”。
5.退出连接:
输入exit并按enter键断开与服务器的连接,服务器端界面和客户端界面同时提示“exit\nclose”。
(四)算法分析
ClientServer
(五)程序源代码
A.TCP
1.Client端
#pragmaonce
#include
#include
#pragmacomment(lib,"Ws2_32.lib")
classCClientNet
{
public:
//连接上指定服务器
intConnect(intport,constchar*address);
//发送信息
//intSendMsg(constchar*msg,intlen);
voidSendMsg();
//关闭
voidClose();
private:
SOCKETm_sock;
};
intCClientNet:
:
Connect(intport,constchar*address)
{
intrlt=0;
//用于记录错误信息并输出
intiErrMsg;
//启动WinSock
WSADatawsaData;
iErrMsg=WSAStartup(MAKEWORD(1,1),&wsaData);
if(iErrMsg!
=NO_ERROR)
{
printf("failedwithwsaStartuperror:
%d\n",iErrMsg);
rlt=1;
returnrlt;
}
//创建Socket
m_sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(m_sock==INVALID_SOCKET)
//创建Socket失败
{
printf("socketfailedwitherror:
%d\n",WSAGetLastError());
rlt=2;
returnrlt;
}
//目标服务器数据
sockaddr_insockaddrServer;
sockaddrServer.sin_family=AF_INET;
sockaddrServer.sin_port=port;//端口号
sockaddrServer.sin_addr.s_addr=inet_addr(address);//将一个点分十进制的IP转换成一个长整数型数
//连接,sock与目标服务器连接
iErrMsg=connect(m_sock,(sockaddr*)&sockaddrServer,sizeof(sockaddrServer));
if(iErrMsg<0)
{
printf("connectfailedwitherror:
%d\n",iErrMsg);
rlt=3;
returnrlt;
}
returnrlt;
}
voidCClientNet:
:
SendMsg()
{
chara[50];
charb[50];
charc[50];
printf("login:
\n");
gets(b);
send(m_sock,b,sizeof(b),0);
charrecvBuf[50];
recv(m_sock,recvBuf,50,0);
printf("%s\n",recvBuf);
gets(c);
send(m_sock,c,sizeof(c),0);
recv(m_sock,recvBuf,50,0);
printf("%s\n",recvBuf);
while
(1)
{
gets(a);
if(strcmp(a,"exit")==0)
{
send(m_sock,a,sizeof(a),0);
break;
}
else
{
send(m_sock,a,sizeof(a),0);
charrecvBuf[50];
recv(m_sock,recvBuf,50,0);
printf("%s\n",recvBuf);
}
}
}
voidCClientNet:
:
Close()
{
closesocket(m_sock);
}
voidmain()
{
CClientNetclient;
//连接到127.0.0.1(即本地),端口号为8888的服务端
printf("Connect\n");
client.Connect(8888,"127.0.0.1");
//发送消息
client.SendMsg();
//关闭socket
printf("close\n");
client.Close();
system("pause");
}
2.Server端
#pragmaonce
#include
#include
#pragmacomment(lib,"ws2_32.lib")
classCServerNet
{
public:
//初始化服务器,返回0表示成功
intInit(constchar*address,intport);
//更新数据
voidRun();
private:
SOCKETm_sock;
};
intCServerNet:
:
Init(constchar*address,intport)
{
intrlt=0;
//用于记录错误信息,并输出
intiErrorMsg;
//初始化WinSock
WSADatawsaData;
iErrorMsg=WSAStartup(MAKEWORD(1,1),&wsaData);
if(iErrorMsg!
=NO_ERROR)
{
//初始化WinSock失败
printf("wsastartupfailedwitherror:
%d\n",iErrorMsg);
rlt=1;
returnrlt;
}
//创建服务端Socket
m_sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(m_sock==INVALID_SOCKET)
{
//创建Socket异常
printf("socketfailedwitherror:
%d\n",WSAGetLastError());
rlt=2;
returnrlt;
}
//声明信息
sockaddr_inserverAddr;
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=port;
serverAddr.sin_addr.s_addr=inet_addr(address);
//绑定
iErrorMsg=bind(m_sock,(sockaddr*)&serverAddr,sizeof(serverAddr));
if(iErrorMsg<0)
{
//绑定失败
printf("bindfailedwitherror:
%d\n",iErrorMsg);
rlt=3;
returnrlt;
}
returnrlt;
}
voidCServerNet:
:
Run()
{
//公开连接
listen(m_sock,5);
sockaddr_intcpAddr;
intlen=sizeof(sockaddr);
SOCKETnewSocket;
charbuf[1024];
intrval;
characc[]="aaa";
charpawd[]="123";
intcomp1,comp2,flag1=1,flag2=1;
SOCKETsockConn=accept(m_sock,(sockaddr*)&tcpAddr,&len);
while(flag1==1)
{
charrecvBuf1[50];
recv(sockConn,recvBuf1,50,0);
comp1=strcmp(recvBuf1,acc);
if(comp1==0)
{
send(sockConn,"password:
",strlen("password:
")+1,0);
flag1=0;
}
else
{
send(sockConn,"usernamedoesn'texist,pleaseloginagain:
",strlen("usernamedoesn'texist,pleaseloginagain:
")+1,0);
}
}
while(flag2==1)
{
charrecvBuf2[50];
recv(sockConn,recvBuf2,50,0);
comp2=strcmp(recvBuf2,pawd);
if(comp2==0)
{
send(sockConn,"sendyourmessage:
",strlen("sendyourmessage:
")+1,0);
flag2=0;
}
else
{
send(sockConn,"wrongpassword,pleasetypethepasswordagain:
",strlen("wrongpassword,pleasetypethepasswordagain:
")+1,0);
}
}
while
(1)
{
charrecvBuf[50];
recv(sockConn,recvBuf,50,0);
if(strcmp(recvBuf,"exit")==0)
{
printf("%s\n",recvBuf);
break;
}
else
{
printf("%s\n",recvBuf);
charsendBuf[50];
sprintf(sendBuf,"sendsuccessfully");
send(sockConn,sendBuf,strlen(sendBuf)+1,0);
}
}
//关闭自身的Socket
printf("close\n");
closesocket(m_sock);
}
intmain(intargc,char**argv)
{
CServerNetserverNet;
intiRlt=serverNet.Init("127.0.0.1",8888);
if(iRlt==0)
{
printf("initok...\n");
serverNet.Run();
}
else
printf("serverNetinitfailedwitherror:
%d\n",iRlt);
system("pause");
}
B.UDP
1.Client端
#pragmaonce
#include
#include
usingnamespacestd;
#pragmacomment(lib,"ws2_32.lib")
voidmain()
{
structsockaddr_inm_lsockaddr;
structsockaddr_inm_rsockaddr;
SOCKETm_connectSocket;
memset(&m_lsockaddr,0,sizeof(structsockaddr_in));
//--------初始化winsock环境-------------
WSADATAwsaD;
intresult=WSAStartup((WORD)(1<<8|1),&wsaD);//初始化WinSocket动态连接库;
if(result!
=0)//初始化失败;
{
return;
}
//---------创建一个鉴听SOCKET句柄-----------
if((m_connectSocket=socket(AF_INET,SOCK_DGRAM,0))==INVALID_SOCKET)
{
return;
}
//---------绑定到指定的主机与端口号----------
memset(&m_rsockaddr,0,sizeof(structsockaddr_in));
m_lsockaddr.sin_family=AF_INET;
m_lsockaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
m_lsockaddr.sin_port=htons(7070);
if(bind(m_connectSocket,(SOCKADDR*)&m_lsockaddr,sizeof(structsockaddr_in))==SOCKET_ERROR)
{
return;
}
//---------发送信息给服务器--------------
chara[50];
charb[50];
charc[50];
charrecvBuf[50];
intret=0;
intlen=sizeof(structsockaddr_in);
cout<<"login:
"<gets(b);
memset(&m_lsockaddr,0,sizeof(structsockaddr_in));
m_rsockaddr.sin_family=AF_INET;
m_rsockaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
m_rsockaddr.sin_port=htons(8080);
if(sendto(m_connectSocket,b,strlen(b),0,(SOCKADDR*)&m_rsockaddr,sizeof(structsockaddr_in))==SOCKET_ERROR)
{
return;
}
ret=recvfrom(m_connectSocket,recvBuf,50,0,(SOCKADDR*)&m_rsockaddr,&len);
if(ret==SOCKET_ERROR)
{
return;
}
recvBuf[ret]='\0';
cout<gets(c);
if(sendto(m_connectSocket,c,strlen(c),0,(SOCKADDR*)&m_rsockaddr,sizeof(structsockaddr_in))==SOCKET_ERROR)
{
return;
}
ret=recvfrom(m_connectSocket,recvBuf,50,0,(SOCKADDR*)&m_rsockaddr,&len);
if(ret==SOCKET_ERROR)
{
return;
}
recvBuf[ret]='\0';
cout<while
(1)
{
gets(