江南大学TCPIP群聊私聊设计_第1页
江南大学TCPIP群聊私聊设计_第2页
江南大学TCPIP群聊私聊设计_第3页
江南大学TCPIP群聊私聊设计_第4页
江南大学TCPIP群聊私聊设计_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、TCP/IP网络协议大作业 题 目: 基于TCP的网络通信 班 级: 计科1203班 姓 名: 学 号: 1030412313 摘要本实验基于TCP/IP协议实现客户机/服务器模式下带有用户注册,登录验证功能的互联网聊天系统。通过有连接服务为主体,无连接服务为辅,实现一对一私聊和多对多群聊。关键词:TCP/IP UDP Windows Sockets 聊天系统 总体设计1.1基本协议的选取TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议。其中TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流

2、传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送;而UDP则不为IP提供可靠性、流控或差错恢复功能。一般来说,TCP对应的是可靠性要求高的应用,而UDP对应的则是可靠性要求低、传输经济的应用。本次实验基于TCP/IP协议实现基本的聊天功能,包括注册登录,群聊及私聊。1.2通讯终端的介绍按类别,将此聊天系统划分为三大块,分别为: 本地服务器: 本地服务器接收远程服务器转发的消息并显示消息。 远程服务器: 监听客户端的连接请求; 提供注册服务,验证登陆请求; 查看在线人数,发送在线状态; 发送

3、群聊消息及私聊消息。 本地客户端: 发送建立TCP连接的请求操作; 发送注册信息,登陆消息及退出请求;c) 发送群聊消息及私聊消息。1.3 程序基本流程 客户端选择注册信息; 客户端输入注册信息; 服务器接收并处理客户端注册信息; 客户端输入登录信息; 服务器接收并处理登陆信息; 服务器返回登陆成功与否信息; 若登陆成功,客户端选择群聊或私聊; 服务器根据客户端的消息处理群聊或私聊: 若是群聊,则服务器将此消息群发; 若是私聊,则服务器将此消息发送给对应用户;此程序基本通讯流程图如下:Figure 1-3-1客户/服务器程序流程图1.4面向连接的客户/服务器程序的工作流程此程序客户/服务器程序

4、的工作流程可大致简化为一下步骤:a)服务器先用socket函数来建立一个套接字,用这个套接字完成通信的监听。b)用bind函数来绑定一个端口号和IP地址。因为本地计算机可能有多个网址和IP,每一个IP和端口有多个端口。需要指定一个IP和端口进行监听。c)服务器调用listen函数,使服务器的这个端口和IP处于监听状态,等待客户机的连接。d)客户机用socket函数建立一个套接字,设定远程IP和端口。e)客户机调用connect函数连接远程计算机指定的端口。f)服务器用accept函数来接受远程计算机的连接,建立起与客户机之间的通信。g)建立连接以后,客户机用write函数向socket中写入数

5、据。也可以用read函数读取服务器发送来的数据。h)服务器用read函数读取客户机发送来的数据,也可以用write函数来发送数据。i)完成通信以后,用close函数关闭socket连接。 客户端程序2.1客户端运行原理客户端应用程序的工作流程如下: 使用WSAStartup()函数检查系统协议栈的安装情况。其调用格式与服务器端调用格式类似: WSAStartup(0x0202,&wsaData);WSAStartup(MAKEWORD(2,2),&wsaData); 使用socket()或WSASocket()函数创建客户端套接口。其调用格式同服务器端调用格式类似: SOCKE

6、T clientSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 使用connect()或WSAConnect()函数发出与服务器建立连接的请求。常用格式如下:connect(clientSocket,(struct sockaddr*)&serveraddr,sizeof(serveraddr); 连接建立后,使用send()或WSASend()函数发送数据,或使用recv()或WSARecv()函数接收数据。使用closesocket()函数关闭套接口。 最后调用WSACleanup()函数,结束Windows Sockets API的

7、使用。客户端程序流程图如下:Figure 2-2-1程序流程图2.2客户端程序说明1.客户端当前用户结构struct usersint id; /表示第几个用户int isOnline; /表示是否在线char username10; /用户名char passward10; /密码char ip20;users *next; *user,head,userlogin,*user_online;2.客户端连接函数void connect_server(char argv)if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)printf("

8、;Falid to load winsock. n");return;ser_server.sin_family = AF_INET;ser_server.sin_port = htons(iPort);ser_server.sin_addr.s_addr = inet_addr(argv);sClient = socket(AF_INET, SOCK_DGRAM, 0);if (sClient = INVALID_SOCKET)printf("socket() Faild:%dn", WSAGetLastError();return;3.客户端注册函数,此函数为

9、当前用户输入注册信息,并将此信息存储至user结构体链表中。void regist()char username10;char passward10;printf("请输入注册用户名:n");scanf("%s",&username);printf("请输入注册密码:n");scanf("%s",&passward);struct hostent *phostinfo = gethostbyname("");char *p = inet_ntoa (* (struct in_ad

10、dr *)(*phostinfo->h_addr_list) ); strcpy(user->username,username);strcpy(user->passward,passward);/包含ip信息strncpy(user->ip, p, sizeof(user->ip)- 1); user->ip19 = '0'printf("ip:%sn",user->ip);user->id=i;i = i+1;user->isOnline=0; /表示此用户已经注册过4.客户端登陆函数,此函数为当前用

11、户输入登陆信息,并将此信息存储至userlogin结构体中。/登陆函数void login()char username10;char passward10;printf("请输入登陆用户名:n");scanf("%s",&username);printf("请输入登陆密码:n");scanf("%s",&passward);struct hostent *phostinfo = gethostbyname("");char *p = inet_ntoa (* (struct i

12、n_addr *)(*phostinfo->h_addr_list) ); strcpy(userlogin.username,username);strcpy(userlogin.passward,passward);strncpy(user->ip, p, sizeof(user->ip)- 1); user->ip19 = '0'5.客户端检测函数:此函数检测客户端的登陆用户名和密码是否正确,通过与服务器存储的所有用户比较得出此用户的用户名和密码是否正确,如果正确,user_state返回2.void check()int i=1;int iSen

13、d_server;int iRec_server;int iLen = sizeof(ser_server);char buf_recv1;user= head.next;iRec_server = recvfrom(sClient,buf_recv,sizeof(buf_recv),0,(struct sockaddr*)&ser_server,&iLen);user_state = (int)buf_recv0;if(user_state =2)printf("登陆成功:n");send();6.客户端发送函数:此函数为客户端向服务器发送注册和登陆消息,

14、由于发送的是结构体链表,故先将其转换为指针数组发送,再由服务器将其转换为结构体;void send_loginMessage(char argv_server,struct users *usermessage)int buf_len;int pos = 0;int iSend_userMessage;buf_len = sizeof(users);char *buf_send = (char *)malloc(buf_len);memcpy(buf_send,usermessage,buf_len);while(pos<buf_len)iSend_userMessage = sendt

15、o(sClient,buf_send+pos,buf_len,0,(struct sockaddr*)&ser_server,sizeof(ser_server);if(iSend_userMessage=SOCKET_ERROR)printf("send to server Faild.:%dn",WSAGetLastError();break;pos += iSend_userMessage;7. 客户端发送群聊消息,通过选择群聊,服务器向所有在线人员发送消息。void send_message(char *argv_local)int i = 1;int iR

16、ecv;int iSend_server;char buf_sDATA_BUFFER;int iLen = sizeof(ser_server);int iLens = sizeof(users);if(user_state =2)while(i != 0)printf("%s:n",user->name);char buf_sendSEND_NAME;scanf("%s", &buf_s);strcat(buf_send, buf_s);iSend_server = sendto(sClient, buf_send, sizeof(buf

17、_send), 0, (struct sockaddr*)&ser_server, iLen);if(iSend_server=SOCKET_ERROR)printf("send to server Faild.:%dn",WSAGetLastError();/发送IP到服务器if (stricmp(buf_s, "exit") = 0)break;else if(user_state = 1)printf("用户登录失败,此用户已经登录.n");else printf("用户登录失败,未注册或密码错误.n"

18、;);8. 客户端发送私聊消息:如果客户端通过提示选择私聊,将得到服务器发送回的当前在线人员,选择当前在线人员开启私聊。void send_message_s(char *argv_local)int i = 1;int iRecv;int pos = 0;int iSend_server;char buf_sDATA_BUFFER;int iLens = sizeof(users);int iLen = sizeof(ser_server);if(user_state =2)while(i != 0)printf("%s:n",user->name);char bu

19、f_sendSEND_NAME = "涂序文:"scanf("%s", &buf_s);strcat(buf_send, buf_s);iSend_server = sendto(sClient, buf_send, sizeof(buf_send), 0, (struct sockaddr*)&ser_server, iLen);if(iSend_server=SOCKET_ERROR)printf("send to server Faild.:%dn",WSAGetLastError();char *buf_rev

20、 = (char *)malloc(iLens);while(pos<iLens)iRecv = recvfrom(sClient,buf_rev+pos,iLens,0,(sockaddr*)&ser_server,&iLen);if(iRecv=SOCKET_ERROR)printf("rec_regist Faild.:%dn",WSAGetLastError();break;pos += iRecv;user_online = (struct users *)malloc(sizeof(struct users);memcpy(user_onl

21、ine,buf_rev,iLens);printf("%dn",user_online->isOnline);/iRecv = recvfrom(sClient,*name_rev,sizeof(*name_rev),0,(struct sockaddr*)&ser_server,&iLen);if (stricmp(buf_s, "exit") = 0)break;else if(user_state = 1)printf("此用户已经登录.n");else printf("未注册或密码错误.n&qu

22、ot;);2.3本地服务器程序#include<Winsock2.h>#include<stdio.h>#include<stdlib.h>#pragma comment(lib,"ws2_32.lib") #define DEFAULT_PORT 5056void main()int iPort = DEFAULT_PORT;WSADATA WSAData;SOCKET sSocket, sAccept;int iLen;int iSend;char buf1024;char buf_send = "copy"str

23、uct sockaddr_in ser;printf("-n");printf("Server waittingn");printf("-n");if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)printf("Faild to load WinSock.n");return;sSocket = socket(AF_INET, SOCK_DGRAM, 0);if (sSocket = INVALID_SOCKET)printf("socket()Faild

24、:%dn", 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:%dn", WSAGetLastError();return;iLen = sizeof(ser);memset(buf, 0, sizeof(b

25、uf);while (1)iLen = recvfrom(sSocket, buf, sizeof(buf), 0,(sockaddr*)&ser,&iLen);printf("%sn",&buf);if (stricmp(buf, "exit") = 0)printf("用户退出,服务器即将退出.");break;closesocket(sSocket);WSACleanup(); 服务器程序3.1服务器运行原理a)使用WSAStartup()函数检查系统协议栈的安装情况。b)使用socket()或WSASo

26、cket()函数创建服务器端通信的套接口。如果套接口创建不成功,也不能执行以下的各操作,并且要调用WSACleanup(),结束Windows Sockets API的使用。这一步调用过程确定了相关五元组的协议。c)使用bind()函数将创建的套接口与服务器地址绑定。它确定了相关五元组中的本地IP地址和端口号。d)使用listen()函数使服务器套接口做好接收连接请求的准备。e)使用accept()或WSAAccept()函数接收来自客户端由connect()。f)连接建立连接后,使用send()或WSASend()函数发送数据,或使用recv()或WSARecv()函数接收数据。g)使用cl

27、osesocket()函数关闭套接口。h)最后调用WSACleanup()函数,结束结束Windows Sockets API的使用。服务器运行原理如下:Figure 3-1 服务器工作流程图3.2服务器程序说明1. 服务器当前用户结构struct usersint id;int isOnline;char username10;char passward10;char ip20;users *next;*user,login,head,tail,*user_check,login_all10;2. 服务器连接函数,此函数将基本连接函数剥离出来void connect()int iPort =

28、 DEFAULT_PORT;/int yPort = DEFAULT_PORT_1;if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0)printf("Faild to load WinSock.n");return;sSocket = socket(AF_INET,SOCK_DGRAM,0);if(sSocket = INVALID_SOCKET)printf("socket() Faild:%dn",WSAGetLastError();return;ser.sin_family = AF_INET;ser.sin

29、_port = htons(iPort);ser.sin_addr.s_addr = htonl(INADDR_ANY);cli.sin_family = AF_INET;cli.sin_port = htons(iPort);if (bind(sSocket, (LPSOCKADDR)&ser, sizeof(ser) = SOCKET_ERROR)printf("bind-()Faild:%dn", WSAGetLastError();return;iLens = sizeof(cli);3.服务器接收函数,此函数接收客户端的注册信息,并将此信息存储至user结

30、构体链表中。/接收注册信息void rec_regist()int iLen = sizeof(users);int pos = 0;int iRecv_user;char *buf_rev = (char *)malloc(iLen);user = tail.next;while(pos<iLen)iRecv_user = recvfrom(sSocket,buf_rev+pos,iLen,0,(sockaddr*)&cli,&iLens);if(iRecv_user=SOCKET_ERROR)printf("rec_regist Faild.:%dn&quo

31、t;,WSAGetLastError();break;pos += iRecv_user;memcpy(user,buf_rev,iLen);printf("用户%s注册成功.n",user->username);printf("ip:%sn",user->ip);user->isOnline = 0;user->next = (struct users *)malloc(sizeof(struct users);user = user->next;tail.next = user;user->id = 0;4.服务器

32、接收登陆函数,此函数为服务器接收当前用户输入登陆信息,并将此信息存储至userlogin结构体中。/登陆函数void login()char username10;char passward10;printf("请输入登陆用户名:n");scanf("%s",&username);printf("请输入登陆密码:n");scanf("%s",&passward);struct hostent *phostinfo = gethostbyname("");char *p = ine

33、t_ntoa (* (struct in_addr *)(*phostinfo->h_addr_list) ); strcpy(userlogin.username,username);strcpy(userlogin.passward,passward);strncpy(user->ip, p, sizeof(user->ip)- 1); user->ip19 = '0'5.服务器检测函数:此函数检测客户端的登陆用户名和密码是否正确,通过与本地存储的所有用户比较得出此用户的用户名和密码是否正确,如果正确,user_state返回2。如果用户已登录,us

34、er->isOnline= 2;如果用户密码正确但未登录,user->isOnline = 1;否则user->isOnline = 0;/检测函数void check()int i=1;int iSend_local;int iLen;char buf_send1;user= head.next;while(i=user->id)/输入的用户名和密码正确if(strcmp(login.username,user->username)=0&&strcmp(login.passward,user->passward)=0)/登录成功并已经在线时

35、,不允许登录if(login.isOnline = user->isOnline)printf("登录成功.n");user->isOnline = 1;login.isOnline = 2;break;elselogin.isOnline = 1;printf("此用户已经登录.n");user = user->next;i = i+1;*buf_send = (char)login.isOnline;iSend_local = sendto(sSocket,buf_send,sizeof(buf_send),0,(struct so

36、ckaddr*)&cli,iLens);recv();6.服务器接收函数:此函数为服务器接收到客户端请求群聊,得到所有在线的人数并得到其ip,将客户端需要发送的消息发送给各个本地服务器。/群聊void recv_message()int i = 1;int iRec_local,iSend_local;if(login.isOnline = 2)user = head.next;while(i!=0)char buf_rev1024;iRec_local = recvfrom(sSocket,buf_rev,sizeof(buf_rev),0,(sockaddr*)&cli,&

37、amp;iLens); /放消息,此消息为用户名字信息if(iRec_local=SOCKET_ERROR)printf("rec_regist Faild.:%dn",WSAGetLastError();elseprintf("%sn",buf_rev);while(user->id!=0)printf("ip:%sn",user->ip);printf("%d",user->isOnline);if(user->ip!=NULL&&user->isOnline=1)

38、printf("当前在线用户:%sn",user->username);cli.sin_addr.s_addr = inet_addr(user->ip); /重置客户端ipiSend_local = sendto(sSocket,buf_rev,sizeof(buf_rev),0,(struct sockaddr*)&cli,iLens);user = user->next;if (stricmp(buf_rev, "exit") = 0)break;else if(login.isOnline= 1)printf("

39、;此用户已经登录,不可重复登录.n");else printf("用户登录失败,未注册或密码错误.n");7. 服务器接收函数:服务器接收到私聊请求执行此函数,服务器得到所有在线人数并将其返回给客户端,客户端选择要私聊的人并由服务器转发给其本地服务器。/私聊void recv_message_s()int pos = 0;int i = 1;int num = 0;int iRec_local,iSend_local;if(login.isOnline = 2)while(i!=0)char buf_rev1024;char buf_revip1024;iRec_

40、local = recvfrom(sSocket,buf_rev,sizeof(buf_rev),0,(sockaddr*)&cli,&iLens); /放消息,此消息为用户名字信息if(iRec_local=SOCKET_ERROR)printf("rec_regist Faild.:%dn",WSAGetLastError();elseprintf("%sn",buf_rev);user = head.next;while(user->id!=0)if(user->ip!=NULL&&user->isOnline = 1)printf("当前在线用户:%

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论