计算机网络第一次实验:利用Socket,设计和编写一个聊天程序
基本要求
-
设计一个两人聊天协议,要求聊天信息带有时间标签。
-
对聊天程序进行设计。
-
在Windows系统下,利用C/C++中的流式Socket对设计的程序进行实现。程序界面可以采用命令行方式,但需要给出使用方法。
-
对实现的程序进行测试。
-
撰写实验报告,并将实验报告和源码提交至本网站。
基本功能概述
- 两人互相聊天通信;
- TCP协议,流式套接字;
- 支持包括但不限于中文、英文等发送;
- 合理的用户上线下线机制;
- 正常的用户退出方式。
代码运行环境
VS2019,使用的包包括:
#include<stdio.h>
#include<string.h>
#include<WinSock2.h>
#include<time.h>
#include<string>
#include<iostream>
#pragma comment (lib,"ws2_32.lib")
聊天协议
在该聊天室程序的两端server和client都遵循如下聊天协议,符合协议的对等性。
语法
报文包括三个数据段,从高位到低位,第一个数据段表示发送/接受时间,第二个数据段表示发送者的昵称,第三段表示发送的信息。数据段之间用一些文字相连,更加直观。报文结构如下所示:
发送消息,消息具体细节如下:
发送时间:2021/10/18 22:36:55 Monday
发送人:413123123
消息:3123123
接收消息,消息具体细节如下:
发送时间:2021/10/18 22:36:55 Monday
发送人:13132123
消息:312312312
其中规定,报文的最大总长度为512,姓名的最大总长度为16
语义及时序
如下图所示:
服务器端
使用socket之前要进行版本的设定和初始化,应用程序只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数。根据版本初始化windows socket,返回0表示成功。然后创建套接字,使用TCP协议。
运行server.cpp,先输入这一端聊天者的昵称,然后保存昵称。接下来服务器建立socket,执行bind操作后,进入listen状态。
在listen状态中,server等待client的connect请求,一旦受到connect请求,就会执行accept,输出连接成功的消息,传入欢迎socket和用户的连接socket,建立一个新的服务器连接socket。accept()是一个阻塞函数,如果没有客户端请求,连接会一直等待在这里。该函数会返回一个新的套接字,这个新的套接字是用来与客户端通信的套接字,之前那个套接字是用来监听的套接字。
在创建完新线程后,在线程中接收client发送的报文信息,若收到了client发送的消息,则执行recvFun函数,在服务器端显示已经收到该信息并将该信息的具体细节显示出来。
同时服务器端也会进行发送操作,当一方输入需要发送的消息时,sendFun函数会将发送消息时的时间,发送人,和具体消息的信息进行打包,并将该消息整体发送到用户端,由用户端接收。
用户端
在使用Socket前先加载套接字库,创建套接字WSAStartup(),然后连接服务器的ip,因为现在服务器端就是本机,所以写本机ip,127.0.0.1一个特殊的IP地址,表示是本机的IP地址。
运行client.cpp,先输入这一端聊天者的昵称,然后保存昵称。接下来服务器建立socket,执行bind操作,并发出连接请求(connect())与客户端进行连接,若成功能连接到客户端,则输出连接成功的消息,如果没有成功连接到服务器,则一直循环,直至连接上为止。此时正式开始两人聊天过程。
在与客户端完成连接后,在线程中接收client发送的报文信息,同时在用户端显示已经收到该信息并将该信息的具体细节显示出来。
与此同时,用户端也可以进行发送操作。当一方输入需要发送的消息时,sendFun函数会将发送消息时的时间,发送人,和具体消息的信息进行打包,并将该消息整体发送到客户端,由客户端接收。因为此时send和recv在两个不同的线程之中,所以不会造成干扰。
核心代码片段设计
建立通信Socket和发送接收线程
SOCKET sockClient;//全局变量,用于通信的socket
//两个线程用于接收和发送信息
void sendFun(