云南大学软件学院计算机网络原理实验三.doc (1).doc
《云南大学软件学院计算机网络原理实验三.doc (1).doc》由会员分享,可在线阅读,更多相关《云南大学软件学院计算机网络原理实验三.doc (1).doc(6页珍藏版)》请在冰豆网上搜索。
云南大学软件学院
实验报告
课程:
计算机网络原理实验任课教师:
金鑫
姓名:
学号:
2016专业:
软件工程成绩:
实验三、套接字编程
1.实验目的:
两人一组,编写一个客户端、服务器程序,掌握Socket编程原理。
2.实验环境:
连入局域网络的主机一台。
3.实验指导:
SocketAPI是实现进程间通信的一种编程设施,也是一种为进程间提供底层抽象的机制。
理解socket编程模型及其原理。
4.实验分析,回答下列问题。
a.运行指导书中的程序,并回答下列问题:
(1)为什么在服务器和客户端要包含winsock2.h文件?
答:
winsock2.h是头文件,声明了在C/C++下进行Winsock编程需要的函数,结构等内容.是提供给编译器用的。
以此来提供自带程序库。
(2)为什么在服务器和客户端程序中要加入#pragmacomment(lib,"ws2_32.lib")语句,如果不加会出现什么问题?
答:
表示链接Ws2_32.lib这个库,否则就无法使用Ws2_32.lib库。
(3)为什么在服务器和客户端程序中要使用WSAStartup函数,如果不用程序会有什么问题?
答:
当调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的
Socket库,然后绑定找到的Socket库到该应用程序中。
以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。
如果不调用就无法完成上述功能。
(4)如果先运行客户端程序,程序会有什么现象,为什么会有这一现象?
答:
客户端闪退,没有建立套接口连接。
(5)如果服务器程序所在计算机没有连接网络,程序会发生什么错误?
我们捕获到什么错误信息?
答:
内容不能够发出去,服务器不接收文件,发生错误。
(6)服务器端程序中“SOCKETsock,msgsock;”这句为什么要定义两个套接字变量?
答:
一个是初始就没有的,另一个是客户端建立连接时分配的,目的是为了多台电脑连接时发生连接冲突。
b.修改服务器和客户端程序代码实现基本交互的功能(自己思考),附上修改后的源代码(修改部分用红色标记,并加关键代码注释)。
客户端:
#include
#include
#include
#include
#pragmacomment(lib,"ws2_32.lib")
#definePORT3490/*客户机连接远程主机的端口*/
#defineMAXDATASIZE100/*每次可以接收的最大字节*/
int_tmain(intargc,_TCHAR*argv[])
{
WORDwVersionRequested;
WSADATAwsaData;
interr=0,rval=0;
SOCKETfd;
structsockaddr_inservaddr;
structhostent*hp;
charbuf[1024]="",*a="服务器连接已关闭",b;
wVersionRequested=MAKEWORD(2,2);
err=WSAStartup(wVersionRequested,&wsaData);
if(err!
=0)
return-1;
if((fd=socket(AF_INET,SOCK_STREAM,0))<0)
{
printf("Cannotcreatesocket!
");
exit
(2);
}
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(PORT);
servaddr.sin_addr.S_un.S_addr=inet_addr("113.55.16.17");
memset(servaddr.sin_zero,0,sizeof(servaddr.sin_zero));
//和服务器创建连接
rval=connect(fd,(sockaddr*)&servaddr,sizeof(servaddr));
if(rval<0)
{//创建连接失败
printf("Cannotcreateconnect!
");
exit(3);
}
else
{
for(;;)
{
memset(buf,0,1024);
printf("请向服务器端发送消息:
");
scanf("%s",&buf);
//向服务器发送信息
rval=send(fd,buf,strlen(buf)+1,0);
if(rval<0)
printf("Writeerror!
");
if((rval=recv(fd,buf,sizeof(buf),0)<0))
perror("readingstreammessage");
if(rval==0)
{
printf("收到服务器的消息:
%s\n",buf);
if(strcmp(buf,a)==0)
{
printf("关闭连接,请输入任意字符退出");
fflush(stdin);
getchar();
closesocket(fd);
exit
(1);
}
}
/*if(rval==)*/
}
}
closesocket(fd);
exit(5);
return0;
}
服务器端:
//1.c.cpp:
定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include"stdafx.h"
#include
#include
#include
#include
#pragmacomment(lib,"ws2_32.lib")
#defineMYPORT3490/*定义用户连接端口*/
#defineBACKLOG10/*多少等待连接控制*/
#defineSERVER_IP_ADDR"113.55.16.17
"/*服务器的IP地址*/
int_tmain(intargc,_TCHAR*argv[])
{
SOCKETsock,msgsock;
intlength=0;
structsockaddr_inserver;
structsockaddrtcpaddr;
charbuf[1024]="",*buff="服务器连接已关闭";
intrval=0,len=0,err=0;
WORDwVersionRequested;
WSADATAwsaData;
/*指定socket版本,否则创建socket失败,即使创建socket返回值不为-1,但是bind时会失败*/
wVersionRequested=MAKEWORD(2,2);
err=WSAStartup(wVersionRequested,&wsaData);
if(err!
=0)
return-1;
/*建立套接字*/
sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("openingstreamsocket");
exit
(1);
}
/*使用任意端口命名套接字*/
server.sin_family=AF_INET;
server.sin_port=htons(MYPORT);
server.sin_addr.s_addr=inet_addr(SERVER_IP_ADDR);
memset(server.sin_zero,0,sizeof(server.sin_zero));
//将服务器地址与socket绑定在一起
rval=bind(sock,(structsockaddr*)&server,sizeof(server));
if(rval<0)
{
perror("bindingstreamsocket");
exit
(1);
}
//找出指定的端口号并打印出来
length=sizeof(server);
if(getsockname(sock,(structsockaddr*)&server,&length)<0)
{
perror("gettingsocketname");
exit
(1);
}
printf("socketport#%d\n",ntohs(server.sin_port));
//开始接收连接,最大请求数为
listen(sock,5);
len=sizeof(structsockaddr);
do
{msgsock=accept(sock,(structsockaddr*)&tcpaddr,(int*)&len);
if(msgsock==-1)
perror("accept");
else
while
(1)
{memset(buf,0,sizeof(buf));
if((rval=recv(msgsock,buf,sizeof(buf),0)<0))
perror("readingstreammessage");
if(rval==0)
{
if(buf[0]=='#')
{
printf("收到连接结束字符,连接结束,按任意键退出");
rval=send(msgsock,buff,strlen(buff)+1,0);
closesocket(msgsock);
getchar();
getchar();
exit(0);
}
else
printf("收到消息:
%s\n",buf);
}
memset(buf,0,1024);
printf("请输入给客户端的信息:
");
scanf("%s",&buf);
//向客户端发送信息
rval=send(msgsock,buf,strlen(buf)+1,0);
if(rval<0)
printf("Writeerror!
");
}
closesocket(msgsock);
}while(TRUE);
/*因为这个程序已经有了一个无限循环,所以套接字"sock"从来不显式关闭。
然而,当进程被杀死或正常终止时,所有套接字都将自动地被关闭。
*/
closesocket(msgsock);
return0;
}
c.给出修改代码后的服务器端和客户端的程序流程图。
服务器端
客户端
Sock,msgsock=Socket()()
Bind(msgsock)
Listen(msgsock)
Err,fd=Socket()
Connect(fd)
msgsock=Accept(fd)
Recv(msgsock)
Send(fd)
Recv(fd)
Close(fd)
Send(msgsock)
Close(msgsock)
阻塞自己等待客户连接
建立连接
请求数据
应答数据
d.给出程序调试和运行的截图,总结实验过程中出现的问题和解决的办法。
服务器端程序:
客户端程序:
发生的问题及解决办法:
在一开始实验时,不知道需要先运行服务器程序,后面经过试验,知道了需要先打开服务器程序建立连接才能运行客户端程序,另外,需要在代码中添加循环,否则只能数输入一条消息则会退出,加入循环就可以多次输入对话消息。
然后就是用strcmp()函数判断输入的字符串,单当输入#号时,客户端和服务器端程序都能退出。
------------word文档可编辑-------------