服务器回射程序的设计说明.docx
《服务器回射程序的设计说明.docx》由会员分享,可在线阅读,更多相关《服务器回射程序的设计说明.docx(23页珍藏版)》请在冰豆网上搜索。
服务器回射程序的设计说明
网络编程技术实验报告
实验名称
实验四 基于数据报套接字的回射程序设计与实验
队 别
姓 名
学 号
实验日期
2015.12.9
实验报告要求:
1.实验目的 2.实验要求 3.实验环境 4.实验作业 5.问题及解决
6.思考问题 7.实验体会
【实验目的】
1. 巩固套接字编程
2. 熟悉流式套接字编程
【实验要求】
使用流式套接字编程实现回射程序,具体包括:
1.
输出显示。
2. 服务器:
在指定端口上提供服务,接收客户端的发送的回射请求字符串,将接收到的内容回射给
客户端,输出显示。
3. 提炼出网络操作的基本功能,构造网络操作类,修改原有程序
【实验环境】
DEV C++
【实验作业】
网络操作类设计:
class CSocketFrame
{
public:
int start_up();
int clean_up();
int set_address(char *hname,char *sname,struct sockaddr_in *sap,char *protocol);
int quit(SOCKET s);
SOCKET tcp_server(ULONG uIP,USHORT uPort);
SOCKET tcp_server(char *hname,char *sname);
SOCKET tcp_client(char *hname,char *sname);
SOCKET tcp_client(ULONG uIP,USHORT uPort);
};
int CSocketFrame:
:
start_up(void)
{
WORD wVersionRequested;
WSADATA wsaData;
int iResult;
wVersionRequested=MAKEWORD(2,2);
iResult=WSAStartup(wVersionRequested,&wsaData);
if(iResult!
=0)
{
printf("WSAStartup 调用错误,错误号:
%d\n",WSAGetLastError());
return -1;
客户端:
主动请求建立连接,接收界面输入字符串,发送数据给服务器,接收服务器返回的应答,
}
/*
if(LOBYTE(wsaData.wVersion!
=2||HIBYTE(wsaData.wVersion)!
=2))
{
printf("无法找到可用的 WSD 版本\n");
WSACleanup();
return -1;
//告诉用户无法找到可用的 WSD
}
else
{
printf("WS2.2 初始化成功!
\n");
} */
return 0;
}
int CSocketFrame:
:
clean_up(void)
{
int iResult;
iResult=WSACleanup();
if(iResult==SOCKET_ERROR)
{
//WSACleanup()调用失败
printf("WSACleanup 调用错误,错误号:
%d\n",WSAGetLastError());
return -1;
}
else
printf("Winsocket dll 释放成功!
\n") ;
return 0;
}
int CSocketFrame:
:
set_address(char *hname,char *sname,struct sockaddr_in *sap,char
*protocol)
{
struct servent *sp;
struct hostent *hp;
char *endptr;
unsigned short port;
unsigned long ulAddr=INADDR_NONE;
//将地址结构 socketsddr_in 初始化为 0,并将地址族设为 AF_INET
memset(sap,0,sizeof(*sap));
sap->sin_family=AF_INET;
if(hname!
=NULL)
{
//如果 hname 不为空,转化地址格式
ulAddr=inet_addr(hname);
if(ulAddr==INADDR_NONE||ulAddr==INADDR_ANY)
{
//调用错误,调用 gethostbyname 获得主机地址
hp=gethostbyname(hname);
if(hp==NULL)
{
printf("未知的主机名,错误号:
%d\n",WSAGetLastError());
return -1;
}
sap->sin_addr=*(struct in_addr *)hp->h_addr;
}
else
sap->sin_addr.S_un.S_addr=ulAddr;
}
else
//如果调用者没有指明一个主机名或地址,则设为通配地址
sap->sin_addr.s_addr=htonl(INADDR_ANY);
//尝试转换 sname 为一个整数
port=(unsigned short)strtol(sname,&endptr,0);
if(*endptr=='\0')
{
//如果成功转化为网络字节序
sap->sin_port=htons(port);
}
else
{
//如果失败,则假定是一个服务名称,通过 getservbyname()函数获得端口号
sp=getservbyname(sname,protocol);
if(sp==NULL)
{
printf("未知服务,错误号:
%d\n",WSAGetLastError());
return -1;
}
sap->sin_port=sp->s_port;
}
return 0;
}
int CSocketFrame:
:
quit(SOCKET s)
{
int iResult=0;
iResult=closesocket(s);
if(iResult==SOCKET_ERROR)
{
printf("closesocket 调用错误,错误号:
%d\n",WSAGetLastError());
return -1;
}
iResult=clean_up();
return iResult;
}
SOCKET CSocketFrame:
:
tcp_server(char *hname,char *sname)
{
SOCKET ListenSocket;
int iResult=0;
sockaddr_in local;
const int on=1;
//为服务器的本机地址设置用户输入的地址以及端口号
if(set_address(hname,sname,&local,(char*)"tcp")!
=0)
return -1;
//创建套接字
ListenSocket=socket(AF_INET,SOCK_STREAM,0);
if(ListenSocket==INVALID_SOCKET)
{
printf("socket 函数调用错误,错误号:
%d\n",WSAGetLastError());
WSACleanup();
return -1;
}
//绑定服务器地址
iResult=bind(ListenSocket,(struct sockaddr *) & local,sizeof(local));
if(iResult==-1)
{
printf("bind 函数调用错误!
错误号:
%d\n",WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return -1;
}
//设置函数为监听状态,监听队列长度为 NLISTEN
iResult=listen(ListenSocket,SOMAXCONN);
if(iResult==SOCKET_ERROR)
{
printf("Listen 函数调用错误!
错误号:
%d\n",WSAGetLastError());
quit(ListenSocket);
return -1;
}
return ListenSocket;
}
SOCKET CSocketFrame:
:
tcp_server(ULONG uIP,USHORT uPort)
{
SOCKET ListenSocket=INVALID_SOCKET;
int iResult=0;
sockaddr_in local;
const int on=1;
//为服务器的本机地址设置用户输入的地址以及端口号
memset(&local,0,sizeof(local));
local.sin_family=AF_INET;
local.sin_addr.S_un.S_addr=htonl(uIP);
local.sin_port=htons(uPort);
ListenSocket=socket(AF_INET,SOCK_STREAM,0);
if(ListenSocket==INVALID_SOCKET)
{
printf("socket 函数调用错误,错误号:
%d\n",WSAGetLastError());
clean_up();
return -1;
}
//绑定服务器地址
iResult=bind(ListenSocket,(struct sockaddr *) & local,sizeof(local));
if(iResult==SOCKET_ERROR)
{
printf("bind 函数调用错误!
错误号:
%d\n",WSAGetLastError());
quit(ListenSocket);
return -1;
}
//设置函数为监听状态,监听队列长度为 NLISTEN
iResult=listen(ListenSocket,SOMAXCONN);
if(iResult==SOCKET_ERROR)
{
printf("Listen 函数调用错误!
错误号:
%d\n",WSAGetLastError());
quit(ListenSocket);
return -1;
}
return ListenSocket;
}
SOCKET CSocketFrame:
:
tcp_client(char *hname,char *sname)
{
int iResult=0;
struct sockaddr_in peer;
SOCKET ClientSocket;
//为服务器的地址 peer 设置用户输入的地址以及端口号
if(set_address(hname,sname,&peer,(char *)"tcp")!
=0)
return -1;
//创建套接字
ClientSocket=socket(AF_INET,SOCK_STREAM,0);
if(ClientSocket==INVALID_SOCKET)
{
printf("socket 函数调用错误,错误号:
%d\n",WSAGetLastError());
clean_up();
return -1;
}
//请求建立连接
iResult=connect(ClientSocket,(struct sockaddr *) & peer,sizeof(peer));
if(iResult==SOCKET_ERROR)
{
printf("connect 函数调用错误!
错误号:
%d\n",WSAGetLastError());
quit(ClientSocket);
return -1;
}
return ClientSocket;
}
SOCKET CSocketFrame:
:
tcp_client(ULONG uIP,USHORT uPort)
{
int iResult=0;
struct sockaddr_in peer;
SOCKET ClientSocket;
//为服务器的地址 peer 设置用户输入的地址以及端口号
memset(&peer,0,sizeof(peer));
peer.sin_family=AF_INET;
peer.sin_addr.S_un.S_addr=htonl(uIP);
peer.sin_port=htons(uPort);
//创建套接字
ClientSocket=socket(AF_INET,SOCK_STREAM,0);
if(ClientSocket==INVALID_SOCKET)
{
printf("socket 函数调用错误,错误号:
%d\n",WSAGetLastError());
clean_up();
return -1;
}
//请求建立连接
iResult=connect(ClientSocket,(struct sockaddr *) & peer,sizeof(peer));
if(iResult==SOCKET_ERROR)
{
printf("connect 函数调用错误!
错误号:
%d\n",WSAGetLastError());
quit(ClientSocket);
return -1;
}
return ClientSocket;
}
服务器代码设计:
#define MAXLINE 10000
#define ECHOPORT "7210"
int tcp_server_fun_echo(SOCKET s)
{
int iResult = 0;
char recvline[MAXLINE];
do
{
memset(recvline, 0, MAXLINE);
//接收数据
iResult = recv(s, recvline, MAXLINE, 0);
if (iResult > 0)
{
printf("服务器接收到数据:
%s\n", recvline);
//回射程序已经收到的数据
iResult = send(s, recvline, iResult, 0);
if (iResult == SOCKET_ERROR)
{
printf("send 函数调用错误,错误号:
%ld\n", WSAGetLastError());
iResult = -1;
}
else
printf("服务器发送数据%s\n", recvline);
}
else
{
if (iResult == 0)
printf("对方连接关闭,退出\n");
else
{
printf("recv 函数调用错误,错误号:
%d\n", WSAGetLastError());
iResult = -1;
}
break;
}
} while (iResult > 0);
return iResult;
}
int main(int argc, char* argv[])
{
CSocketFrame frame;
int iResult = 0;
SOCKET ListenSocket, ConnectSocket;
//输入参数合法性检查
if (argc !
= 1)
{
printf("usage:
EchoTCPServer");
return -1;
}
//初始化
frame.start_up();
//创建服务器的流式套接字并在指定端口号上监听
ListenSocket =frame.tcp_server((char *)NULL,(char *)ECHOPORT); //改成全部任意
if (ListenSocket == -1)
return -1;
printf("服务器准备好回射服务。
。
。
\n");
for (;;)
{
ConnectSocket = accept(ListenSocket, NULL, NULL);
if (ConnectSocket !
= INVALID_SOCKET)
{
//建立连接成功
printf("\r\n 建立连接成功\n\n");
//回射
iResult = tcp_server_fun_echo(ConnectSocket);
//如果出错,关闭当前连接的套接字,继续接受其他客户端的请求
if (iResult == -1)
printf("当前连接已关闭或出错!
\n");
}
else
{
printf("accept 函数调用错误,错误号:
%d\n", WSAGetLastError());
frame.quit(ListenSocket);
return -1;
}
//关闭套接字
if (closesocket(ConnectSocket) == SOCKET_ERROR)
printf("closesocket 函数调用错误,错误号:
%d\n", WSAGetLastError());
}
frame.quit(ListenSocket);
return 0;
}
客户端代码设计:
#define ECHOPORT "7210"
#define MAXLINE 10000
int tcp_client_fun_echo(FILE *fp,SOCKET s)
{
int iResult;
char sendline[MAXLINE],recvline[MAXLINE];
//初始化缓冲区
memset(sendline,0,MAXLINE);
memset(recvline,0,MAXLINE);
//循环发送用户输入的数据,并接受服务器返回的应答,直到用户输入 Q 结束
while(fgets(sendline,MAXLINE,fp)!
=NULL)
{
if(*sendline=='Q')
{
printf("input end!
\n");
//用户发送数据结束
iResult=shutdown(s,SD_SEND);
if(iResult==SOCKET_ERROR)
{
printf("shutdown 函数调用错误,错误号:
%d",WSAGetLastError());
}
return 0;
}
iResult=send(s,sendline,strlen(sendline),0);
if(iResult==SOCKET_ERROR)
{
printf("send 函数调用错误,错误号:
%d",WSAGetLastError());
return -1;
}
printf("\r\n 客户端发送数据:
%s\r\n",sendline);
memset(recvline,0,MAXLINE);
iResult=recv(s,recvline,MAXLINE,0);
if(iResult>0)
printf("客户端收到数据:
%s\r\n",recvline);
else
{
if(iResult==0)
printf("服务器终止!
\n");
else
printf("recv 函数调用错误,错误号:
%d",WSAGetLastError());
break;
}
memset(sendline,0,MAXLINE);
}
return iResult;
}
int main(int argc,char *argv[])
{
CSocketFrame frame;
int iResult;
SOCKET ClientSocket;
//输入参数合法性检查
/*
if(argc!
=2)
{
printf("usage:
EchoTCPServer");
return -1;
} */
//WSD 初始化
frame.start_up();
//创建客户端的流式套接字
printf("连接成功,请输入回射字符串。
。
。
\n");
ClientSocket=frame.tcp_client((char *)argv[1],(char *)ECHOPORT);
if(ClientSocket==-1)
return -1;
//开始回射请求的发送与接收
iResult=tcp_client_fun_echo(stdin,ClientSocket);
frame.quit(ClientSocket);
}
实验结果:
我是在两台不同的电脑上做的实验,实验结果如下:
服务器:
客户端:
【实验中出现问题及解决方法】
1. 平台的问题
因为自己是使用 win10 的,开始装上 Visual Studio 2015 出现了很多问题,比如库文件缺失,
相关项目类型没有装的问题。
解决方法:
暂时使用 DEV C++,然后自己对 VS 进行相关配置,已经差不多了,后续会尝试转移到 VS 平台。
【思考问题】
(自己在试验过程中想到的问题)
1.如果服务器端口号设定为任意可不可以?
不可以,因为客户端会不知道服务器的端口。
2.上述设计的服务器有没有考虑多个客户端的问题?
可以多个客户端同时连接成功,但是只有首先连入的那个可以与服务器进行通信!
【实验体会】
因为涉及到网络操作结构类的构造,代码量比较大,当然很多在本节中并没有使用,但考虑到日后
要进行使用,减少后续编程的工作量,在本次结构体设计中,对可能用到的基本操作进行了一次性的设
计。
但是后续的工作就进行的比较顺利。
还是比较有自豪感的!
因为参考了试验课本,以后仍需勤加练
习,才能够更好地掌握流式套接字编程。
成绩
优
良
中
及格
不及格
教师签名:
日期: