TCPIP大作业基于TCP的网络通信编程C语言版江南大学.doc
《TCPIP大作业基于TCP的网络通信编程C语言版江南大学.doc》由会员分享,可在线阅读,更多相关《TCPIP大作业基于TCP的网络通信编程C语言版江南大学.doc(44页珍藏版)》请在冰点文库上搜索。
TCP/IP协议编程大作业
课题名称基于TCP的网络通信
专业计算机科学与技术
班级计算机1206
学号1030412612
学生姓名王成义
物联网工程学院
摘要
此TCP/IP课程设计实现了基于TCP的客户/服务器通信程序,具体实验过程通过有连接服务为主体,无连接服务为辅并利用事件对象I/O管理来实现。
客户机具有注册,登陆,单聊,私聊,在线人数列表,退出等功能。
目录
一、总体设计 4
1、基本通信协议选取 4
2、通信过程设计 4
3、通信过程数据包设计 4
4、程序流程图 5
二、客户端程序 6
1、功能:
6
2、原理:
6
3、程序清单 6
三、服务器端程序 19
1、功能:
19
2、原理:
19
3、程序清单:
19
四、运行结果 35
1、服务器端截图 35
2、客户端截图 37
一、总体设计
1、基本通信协议选取
TCP(TransmissionControlProtocol)和UDP(UserDatagramProtocol)协议属于传输层协议。
TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。
通过面向连接、端到端和可靠的数据包发送。
而UDP则不为IP提供可靠性、流控或差错恢复功能。
TCP对应的是可靠性要求高的应用,而UDP对应的则是可靠性要求低、传输经济的应用。
本次实验基于TCP/IP协议利用事件对象I/O管理实现基本的聊天功能,包括注册,登录,群聊,私聊及在线人数统计。
2、通信过程设计
2.1客户端设计
a.本地服务器
主要功能:
1)接收远程服务器转发的消息并显示消息。
b.本地客户端
主要功能:
1)发送建立TCP连接的请求操作;
2)发送注册信息,登陆消息及退出请求;
3)发送群聊消息,私聊消息,在线人数统计及退出请求。
2.2服务器端设计
a.远程服务端
主要功能:
1)监听客户端的连接请求;
2)提供注册服务,验证登陆请求和验证功能;
3)查看在线人数,发送在线状态;
4)发送群聊消息及私聊消息。
3、通信过程数据包设计
3.1客户端数据包设计:
a.注册:
‘0’
user(用户名)
‘@’
password(密码)
b.登陆:
‘1’
user(用户名)
‘@’
password(密码)
c.聊天:
0)群聊:
‘2’
user(用户名)
‘@’
str(内容)
1)单聊:
‘5’
str1(单聊对象名)
‘@’
user(用户名)
‘*’
str(内容)
2)在线用户
‘4’
user(用户名)
‘@’
str(内容)
3)退出(登录):
‘3’
user(用户名)
‘@’
3.2服务端数据包设计:
a.注册应答:
‘00’—注册成功
‘01’—注册失败—用户名已存在
b.登陆应答:
‘10’—登陆成功
‘12’—用户名不存在
‘11’—密码不正确
‘1@’—该用户已登陆
c.聊天:
1)单聊:
‘61’—单聊对象不在线
‘50’—单聊对象在线
‘60’—单聊对象不存在
2)群聊:
‘30’—广播消息
‘31’—非正确用户的消息,不广播
3)在线人数:
‘40’—显示当前在线人数并发给查询客户
4、程序流程图
二、客户端程序
1、功能:
1.1注册:
向服务器发送注册信息。
然后接收服务器返回的应答信息。
1.2登陆:
向服务器发送登陆信息。
接收服务器返回的应答信息。
1.3聊天:
登陆成功后,选择群聊或单聊进行聊天,选择在线用户可进行查询当前在线用户,选择退出可退出登录。
a.单聊:
从在线用户中选择一个,与其单聊
b.群聊:
向所有在线的用户发送消息
c.退出聊天:
退出此次聊天,但不断开连接
d.退出登陆,断开连接,退出时不需要发送下线信息,直接退出
1.4面向连接的客户/服务器程序工作模型:
2、原理:
客户机在注册或登陆时首先和服务器连接,注册完或登陆失败断开连接,登陆成功不断开连接,使用send和recv发送接收数据,根据上述的数据报的定义,发送相应的数据报。
3、程序清单
3.1客户端接收器(本地服务器)代码
#include
#include
#include
#include
#pragmacomment(lib,"ws2_32.lib")
#defineDEFAULT_PORT5051//FORRECV
#defineBUFFER_LENGTH1000
voidMySendMessage(SOCKETsSocket,char*response,intresponseLen,structsockaddr*cli,intcliLen);
voidmain()
{
intiPort=DEFAULT_PORT;
WSADATAwsaData;
SOCKETsSocket,wchysSocket;
intiLen,wchyiLen;
intiSend;
intiRecv;
charsend_buf[1000];
charrecv_buf[BUFFER_LENGTH];
structsockaddr_inser,cli,wchy;
printf("----------------------\n");
printf("cServerWaiting\n");
printf("----------------------\n");
if(WSAStartup(MAKEWORD(2,2),&wsaData)!
=0)
{printf("FailedtoloadWinsock.\n");return;}
sSocket=socket(AF_INET,SOCK_DGRAM,0);
if(sSocket==INVALID_SOCKET){printf("socket()Faild:
%d\n",WSAGetLastError());return;}
ser.sin_family=AF_INET;
ser.sin_port=htons(iPort);
ser.sin_addr.s_addr=htonl(INADDR_ANY);
if(bind(sSocket,(LPSOCKADDR)&ser,sizeof(ser))==SOCKET_ERROR)
{printf("bind()Faild:
%d\n",WSAGetLastError());return;}
iLen=sizeof(cli);
memset(recv_buf,0,sizeof(recv_buf));
while
(1)
{
//接收数据包确定cli表示cli存有客户端发来的ip和port
iRecv=recvfrom(sSocket,recv_buf,BUFFER_LENGTH,0,(SOCKADDR*)&cli,&iLen);
if(iRecv==SOCKET_ERROR)
{printf("recvfrom()Faild:
%d\n",WSAGetLastError());return;}
elseif(iRecv==0)break;
else
{//接收到了正确数据
//printf("[+]%s\n",recv_buf);
//控制信息的种类有000110111220213031
//00注册成功01注册失败10登陆成功11.12表示登陆失败20表示一次成功会话21表示错误会话30表示成功推出31表示错误推出
switch(recv_buf[0])
{
case'0':
if(recv_buf[1]=='0')printf("注册成功\n");
elseprintf("注册失败\n");
break;
case'1':
if(recv_buf[1]=='0')
{
printf("登陆成功\n");
wchy.sin_family=AF_INET;
wchy.sin_port=htons(5053);
wchy.sin_addr.s_addr=inet_addr("127.0.0.1");
wchysSocket=socket(AF_INET,SOCK_DGRAM,0);
if(wchysSocket==INVALID_SOCKET)
{printf("socket()Failed:
%d\n",WSAGetLastError());return;}
wchyiLen=sizeof(wchy);
strcpy(send_buf,"##");
MySendMessage(wchysSocket,send_buf,sizeof(send_buf),(structsockaddr*)&wchy,wchyiLen);
}
elseif(recv_buf[1]=='@')
{
printf("已经在其他地方登陆\n");
wchy.sin_family=AF_INET;
wchy.sin_port=htons(5053);
wchy.sin_addr.s_addr=inet_addr("127.0.0.1");
wchysSocket=socket(AF_INET,SOCK_DGRAM,0);
if(wchysSocket==INVALID_SOCKET)
{printf("socket()Failed:
%d\n",WSAGetLastError());return;}
wchyiLen=sizeof(wchy);
strcpy(send_buf,"**");
MySendMessage(wchysSocket,send_buf,sizeof(send_buf),(structsockaddr*)&wchy,wchyiLen);
}
else{
printf("登陆失败\n");
wchy.sin_family=AF_INET;
wchy.sin_port=htons(5053);
wchy.sin_addr.s_addr=inet_addr("127.0.0.1");
wchysSocket=socket(AF_INET,SOCK_DGRAM,0);
if(wchysSocket==INVALID_SOCKET)
{printf("socket()Failed:
%d\n",WSAGetLastError());return;}
wchyiLen=sizeof(wchy);
strcpy(send_buf,"@@");
MySendMessage(wchysSocket,send_buf,sizeof(send_buf),(structsockaddr*)&wchy,wchyiLen);
}
break;
case'2':
printf("[群聊]%s\n",recv_buf+2);
break;
case'4':
printf("在线用户列表:
%s\n",recv_buf+2);
break;
case'5':
printf("[单聊]");
wchy.sin_family=AF_INET;
wchy.sin_port=htons(5053);
wchy.sin_addr.s_addr=inet_addr("127.0.0.1");
wchysSocket=socket(AF_INET,SOCK_DGRAM,0);
if(wchysSocket==INVALID_SOCKET)
{printf("socket()Failed:
%d\n",WSAGetLastError());return;}
wchyiLen=sizeof(wchy);
strcpy(send_buf,"%%");
MySendMessage(wchysSocket,send_buf,sizeof(send_buf),(structsockaddr*)&wchy,wchyiLen);
printf("%s\n",recv_buf+2);
break;
case'6':
if(recv_buf[1]=='0')
{
printf("单聊对象不存在\n");
wchy.sin_family=AF_INET;
wchy.sin_port=htons(5053);
wchy.sin_addr.s_addr=inet_addr("127.0.0.1");
wchysSocket=socket(AF_INET,SOCK_DGRAM,0);
if(wchysSocket==INVALID_SOCKET)
{printf("socket()Failed:
%d\n",WSAGetLastError());return;}
wchyiLen=sizeof(wchy);
strcpy(send_buf,"^^");
MySendMessage(wchysSocket,send_buf,sizeof(send_buf),(structsockaddr*)&wchy,wchyiLen);
}
elseif(recv_buf[1]=='1')
{
printf("单聊对象未在线\n");
wchy.sin_family=AF_INET;
wchy.sin_port=htons(5053);
wchy.sin_addr.s_addr=inet_addr("127.0.0.1");
wchysSocket=socket(AF_INET,SOCK_DGRAM,0);
if(wchysSocket==INVALID_SOCKET)
{printf("socket()Failed:
%d\n",WSAGetLastError());return;}
wchyiLen=sizeof(wchy);
strcpy(send_buf,"&&");
MySendMessage(wchysSocket,send_buf,sizeof(send_buf),(structsockaddr*)&wchy,wchyiLen);
}
break;
}
}
}
closesocket(sSocket);
WSACleanup();
}
voidMySendMessage(SOCKETsSocket,char*response,intresponseLen,structsockaddr*cli,intcliLen)
{
intiSend;
//intsendto(sockets,constvoid*msg,intlen,unsignedintflags,conststructsockaddr*to,inttolen);
iSend=sendto(sSocket,response,responseLen,0,(SOCKADDR*)cli,cliLen);
// iSend=sendto(sClient,send_buf,sizeof(send_buf),0,(structsockaddr*)&ser,iLen);
if(iSend==SOCKET_ERROR)
{
printf("sendto()Failed.:
%d\n",WSAGetLastError());
}
elseif(iSend==0);
else
{
//printf("sendto()succeeded!
\n");
//printf("----------------------\n");
}
}
3.1客户端代码
#include
#include
#include
#pragmacomment(lib,"Ws2_32.lib")
#defineBUFFER_SIZE1024
voidMySendMessage(SOCKETsSocket,char*response,intresponseLen);
intmain(intargc,char**argv)
{
WSADATAwsaData;
sockaddr_inser,cli;
SOCKETsClient,wchysClient;
intiLen,wchyiLen;
intiRecv;
charsend_buf[1000];
charrecv_buf[BUFFER_SIZE];
if(WSAStartup(MAKEWORD(2,2),&wsaData)!
=0)
{
printf("WSAStartup()\n");
return0;
}
printf("手动连接模式中....\n");
charszServer[256]; //连接的服务器地址,IP地址
printf("请输入即将连接的服务器IP地址:
");
gets(szServer);
ser.sin_family=AF_INET;
ser.sin_port=htons(5050);
ser.sin_addr.s_addr=inet_addr(szServer);
charuser[20],password[20];
charstr[100],str1[100],wchystr[100];
boolhasLogin=false;
//只能绑定一次,开始放在了循环里,555
wchysClient=socket(AF_INET,SOCK_DGRAM,0);
if(wchysClient==INVALID_SOCKET){printf("socket()Faild:
%d\n",WSAGetLastError());return0;}
cli.sin_family=AF_INET;
cli.sin_port=htons(5053);
cli.sin_addr.s_addr=htonl(INADDR_ANY);
if(bind(wchysClient,(LPSOCKADDR)&cli,sizeof(cli))==SOCKET_ERROR)
{printf("bind()Faild:
%d\n",WSAGetLastError());return0;}
wchyiLen=sizeof(cli);
memset(recv_buf,0,sizeof(recv_buf));
sClient=socket(AF_INET,SOCK_STREAM,0);
if(sClient==INVALID_SOCKET)
{
printf("socket()\n");
return0;
}
if(connect(sClient,(sockaddr*)&ser,sizeof(ser))==INVALID_SOCKET)
{
printf("socket()\n");
return0;
}
else
{
boolhasLogin=false;
while(!
hasLogin){
printf("--------------------------------\n");
printf("0.注册\n");
printf("1.登陆\n");
printf("2.退出\n");
printf("请输入相应的数字:
\n>");
scanf("%s",&str);
switch(str[0])
{
case'0':
printf("用户名:
");
scanf("%s",user);
printf("密码:
");
scanf("%s",password);
strcpy(send_buf,"0");
strcat(send_buf,user);
strcat(send_buf,"@");
strcat(send_buf,password);
MySendMessage(sClient,send_buf,sizeof(send_buf));
break;
case'1':
printf("用户名:
");
scanf("%s",user);
printf("密码:
");
scanf("%s",password);
strcpy(send_buf,"1");
strcat(send_buf,user);
strcat(send_buf,"@");
strcat(send_buf,password);
MySendMessage(sClient,send_buf,sizeof(send_buf));
iRecv=recvfrom(wchysClient,recv_buf,BUFFER_SIZE,0,(SOCKADDR*)&cli