聊天室的基本要求

聊天器采用客户端/服务器(C/S)模式;
1,客户端利用UDP与服务器连接,客户端与客户端之间通过UDP互相通讯;
2,服务器端具有服务器端口设置,维护客户端个人信息,记录客户端状态,分配账号等功能
客户端具有服务器地址及端口设置,用户注册,用户登陆,添加好友和删除好友,查看好友信 息,给好友发送消息等功能;
3,服务器与客户端间、客户端之间的交互采用控制台方式或GUI窗口方式均可;


聊天器实例的实现情况

1,程序完成了基于客户端/服务器(C/S)模式的设计目标,模拟出类似于QQ聊天室的应用方式,并实现其相关的基本功能。
2,程序完成了基于UDP的设计目标,实现了客户端与服务器,客户端与客户端之间通过UDP互相通讯的设计模式。
3,服务器端实现了具有服务器端口设置,维护客户端个人信息,记录客户端状态等应用功能;客户端实现了具有服务器地址及端口设置,用户注册,用户登陆,给好友发送消息,实现多个用户之间群聊等应用功能。
4,不足之处在于服务器与客户端间、客户端之间采用控制台方式实现了相互交互,未实现基于GUI窗口开发的方式。


运行注意事项(看完再去运行蛤)

这个基于winsock的UDP网络聊天器是本人的期末大作业的内容,因为自己知道做一个课程设计对于很多同学来说难度都太大了,为了让大家能够在更短的时间内有一份可以完整提交的项目以及答辩顺利,所以我无偿的发布出我的大作业供大家学习使用。

项目基于的环境

  • windows操作系统
  • Visual studio 2022 编译器
  • X86(debug)运行架构

网上的项目繁多,所以需要找到适合自己的去学习使用,比如这门课对于苹果电脑的同学就不是很友好。

项目运行须知

同绝大多数的通信实例一样,网络编程对于网络环境的环境&介质要求很高,所以在运行项目之前,请确保运行项目的主机网络的畅通,关闭windows系统的防火墙,连上自己的手机热点做局域网测试效果为佳。

还有要清楚项目的运行逻辑,基于C/S模型的程序实例,一定要记得要先运行服务器,然后在运行客户端,客户端才可以正常访问服务器,并且要注意服务器和客户端的IP与端口信息,这个对于网络通信是非常重要的,很多bug往往不是代码本身的问题,而是出现在了网络配置的问题上,所以如果你是第一在电脑上运行项目,那么第一次就要做好程序在主机上的网络配置,找到代码里有关于网络配置的相关定义进行修改哦。

最后,在用编辑器调试程序运到报错运行不起来时,要学会复制所报出的问题,在百度上搜索问题的答案,这是基本功。


部分实例演示

服务器的运行界面

客户端的运行界面

用户上线提醒

用户注册提醒

私聊功能的实现

群聊功能的实现

聊天室的整体设计

该程序采用经典的c/s架构,即采用客户端/服务器架构。模型的设计包括三个主要部分,即文件存储部分,服务器部分,以及客户端部分。

如图3.1.1所示,其中,服务器的功能为接收发送器的消息请求,并根据消息类型进行不同的响应处理;服务器中通过文件存储用户的用户名和密码。

客户端的功能实现包括两个部分:发送器和接收器。其中发送器所实现的功能包括注册新账号,登录已有账号,发送群聊消息和私聊消息等;接收器主要实现的功能包括接收服务器转发的群聊消息和私聊消息,并将其显示在显示屏上。

服务器要处理的消息类型一共有五种,分别是登录请求、注册请求、群聊消息、私聊消息、退出命令。这五种消息类型,设计使用字符串的第一个字符来进行区分,比如’L‘是Login的首字母,用来作为登录请求的标志,’R‘是Rigister的首字母,用来作为注册请求的标志,’G‘是Group的首字母,用来作为群聊消息的标志,’P’是Personal的首字母,用来作为私聊消息的标志,最后字符串”exit”可以作为用户退出的命令。

服务器要处理的五种消息类型对应着聊天器所要实现的五种功能,即登录功能,注册功能,群聊功能,私聊功能,关闭程序。下文将针对聊天器所要实现的功能给出设计的方案与实现。

聊天室服务器完整代码

#include#include#include#include#include#include#pragma comment(lib,"ws2_32.lib")using namespace std;#define DEFAULT_PORT 5055#define BUFFER_LENGTH 1024class user{public:user(string username, string ip, int sender_port, int receiver_port){this->username = username;this->ip = ip;this->sender_port = sender_port;this->receiver_port = receiver_port;//设置接收器的地址receiver.sin_family = AF_INET;receiver.sin_port = htons(receiver_port);char *addr = new char[ip.length() + 1];strcpy(addr, ip.c_str());receiver.sin_addr.s_addr = inet_addr(addr);}string username;//用户名string ip;//客户端ip地址int sender_port;//发送器端口int receiver_port;//接收器端口struct sockaddr_in receiver;//存储接收器的地址};class server{public:bool Startup(); //检测是否满足服务器运行的环境bool SetServerSocket(); //设置服务器用来监听信息的socket套接字bool Checktxt();//检测存储文件是否存在,若不存在,创建一个void work();//服务器运行的主函数void SendMessage(string message, struct sockaddr_in x); //发送信息的函数void Sendonlinelist();//向客户端发送好友在线列表bool TestUsernameAndPassword(string username, string password, int &flag); //测试用户名和密码是否正确bool TestDuplicateLogin(string username); //测试是否重复登录bool TestDuplicateRigister(string username);//测试是否重复注册string Getusername(string ip, int port); //根据ip和端口号获得用户名intGetuserindex(string username); //根据用户名获得用户在在线用户表的索引号void extractLoginuserinfor(string userinfor, string &username, string &password, string &receiverport); //提取登录请求中的用户名密码和显示器端口号void extractRegisteruserinfor(string userinfor, string&username, string&password); //提取注册请求中的用户名和密码void extactPersonalMessageReceivername(string &message, string &receivername); //提取私聊消息中的接收者的姓名private:WSADATA wsaData;SOCKET sSocket;//用来接收消息的套接字struct sockaddr_in ser;//服务器地址struct sockaddr_in cli;//客户地址int cli_length = sizeof(cli);//客户地址长度char recv_buf[BUFFER_LENGTH];//接收数据的缓冲区vector usertable;//在线用户表string sendmessage, printmessage; //存储服务器转发、打印用的字符串int iSend, iRecv;//存储服务器发送和接收的字符串的长度};bool server::Startup(){if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){cout << "Failed to load Winsock." << endl;return false;}return true;}bool server::SetServerSocket(){//产生服务器端套接口sSocket = socket(AF_INET, SOCK_DGRAM, 0);if (sSocket == INVALID_SOCKET){cout << "socket()Failed:" << WSAGetLastError() << endl;return false;}//建立服务器端地址ser.sin_family = AF_INET;ser.sin_port = htons(DEFAULT_PORT); //htons()函数把一个双字节主机字节顺序的数转换为网络字节顺序的数ser.sin_addr.s_addr = htonl(INADDR_ANY);//htonl()函数把一个主机字节顺序的数转换为网络字节顺序的数 if (bind(sSocket, (LPSOCKADDR)&ser, sizeof(ser)) == SOCKET_ERROR){cout << "bind()Failed:" << WSAGetLastError() << endl;return false;}return true;}void server::SendMessage(string message, struct sockaddr_in x){char *send_buf = new char[message.length() + 1];strcpy(send_buf, message.c_str());SOCKET rSocket = socket(AF_INET, SOCK_DGRAM, 0);if (rSocket == INVALID_SOCKET){cout << "socket()Failed:" << WSAGetLastError() << endl;return;}iSend = sendto(rSocket, send_buf, message.length() + 1, 0, (SOCKADDR*)&(x), sizeof(x));if (iSend == SOCKET_ERROR){cout << "sendto failed:" << WSAGetLastError() << endl;closesocket(rSocket);return;}closesocket(rSocket);}void server::Sendonlinelist(){string onlinelist;for (int i = 0; i < usertable.size(); i++)onlinelist = onlinelist + usertable[i].username + "#";onlinelist = onlinelist + "$";//结束标志SendMessage(onlinelist, cli);}bool server::TestUsernameAndPassword(string username, string password, int &flag){if (!Checktxt()){cout << "无法找到存储文件." << endl << endl;flag = 0; //未找到用户名的标志return false;}fstream in("C:\\userform\\userform.txt");string line;string username_txt, password_txt;while (getline(in, line)){for (int i = 0; i < line.size(); i++){if (line[i] == '#'){username_txt = line.substr(0, i);password_txt = line.substr(i + 1);break;}}if (username_txt == username) //该用户名存在{if (password == password_txt) //且密码正确{in.close();return true;//返回验证成功}cout << "用户" << username << "登录密码错误" << endl << endl; //返回密码错误的信息flag = 1;//密码错误的标志return false;}}in.close();cout << "未注册过的用户:" << username << endl << endl;flag = 0; //未找到用户名的标志return false;}bool server::TestDuplicateLogin(string username){int i;for (i = 0; i < usertable.size(); i++)if (usertable[i].username == username) break;if (i == usertable.size()) //该用户还没有登录过return false;else{cout << "用户" << username << "重复登录" << endl;return true;}}bool server::TestDuplicateRigister(string username){if (!Checktxt()){cout << "无法找到存储文件." << endl << endl;return true;}fstream in("C:\\userform\\userform.txt");string line;while (getline(in, line)){string username_txt;for (int i = 0; i < line.size(); i++){if (line[i] == '#'){username_txt = line.substr(0, i);//提取用户名if (username_txt == username)//对比,相等则表明已经注册过{in.close();cout << "用户名" << username << "重复注册" << endl << endl;return true;}break; //否则继续对比下一个用户名}}}in.close();return false; //代码执行到这说明该用户名还没有注册过}string server::Getusername(string ip, int port){for (int i = 0; i < usertable.size(); i++)if (usertable[i].ip == ip&&usertable[i].sender_port == port)return usertable[i].username;cout << "非法的用户连接上服务器" << endl;cout << "ip地址为:" << ip << endl << "端口号为:" << port << endl;return "";}int server::Getuserindex(string username){int i = 0;for (i = 0; i < usertable.size(); i++)if (usertable[i].username == username) break;return i;}void server::extractLoginuserinfor(string userinfor, string &username, string &password, string &receiverport){int i;for (i = 0; i < userinfor.length(); i++) //提取用户名{if (userinfor[i] == '#'){username = userinfor.substr(0, i);break;}}for (int j = i + 1; j < userinfor.length(); j++)//提取密码和显示器端口号{if (userinfor[j] == '#'){password = userinfor.substr(i + 1, j - i - 1);receiverport = userinfor.substr(j + 1);break;}}}void server::extractRegisteruserinfor(string userinfor, string&username, string&password){for (int i = 0; i < userinfor.size(); i++){if (userinfor[i] == '#'){username = userinfor.substr(0, i);password = userinfor.substr(i + 1);break;}}}void server::extactPersonalMessageReceivername(string &message, string &receivername){for (int i = 0; i < message.size(); i++){if (message[i] == '#'){receivername = message.substr(0, i);message = message.substr(i + 1);break;}}}bool server::Checktxt(){FILE *fp = fopen("C:\\userform\\userform.txt", "r");if (fp == NULL){system("md C:\\userform");ofstream out("C:\\userform\\userform.txt");if (!out)return false;out.close();return true;}return true;}void server::work(){cout << "-----------------" << endl;cout << "Server running" << endl;cout << "-----------------" << endl;while (true) //进入一个无限循环,进行数据接收和发送{memset(recv_buf, 0, sizeof(recv_buf)); //初始化接收缓冲区iRecv = recvfrom(sSocket, recv_buf, BUFFER_LENGTH, 0, (struct sockaddr*)&cli, &cli_length);if (iRecv == SOCKET_ERROR){cout << "recvfrom()Failed:" << WSAGetLastError() << endl;continue;}//获取发送方的地址(ip和端口)char *x = inet_ntoa(cli.sin_addr); string address(x); //获取客户端ipint userport = ntohs(cli.sin_port); //获取客户端端口string infortype = string(recv_buf);//根据infortype[0]来判断消息的类型 if (infortype[0] == 'L')//登录请求{string userinfor = infortype.substr(1); //除去消息类型string username, password, receiver_port;extractLoginuserinfor(userinfor, username, password, receiver_port);//提取用户名和密码//向不合法用户发送登录失败的回应int flag = 0;if (!TestUsernameAndPassword(username, password, flag)){if (flag == 0)SendMessage("0", cli);if (flag == 1)SendMessage("1", cli);continue;}//查询该用户是否重复登录if (TestDuplicateLogin(username)){SendMessage("2", cli);continue;}//将合法的未登录的用户加入列表int receiver_port_int = atoi(receiver_port.c_str());user newuser(username, address, userport, receiver_port_int);usertable.push_back(newuser);printmessage = "(上线消息)" + newuser.username + "已上线"; //设置要打印的消息sendmessage = printmessage; //设置要转发的消息SendMessage("Y", cli);//向客户端发送登录成功的回应}else if (infortype[0] == 'R') //注册信息{string userinfor = infortype.substr(1);//除去消息类型string username, password;extractRegisteruserinfor(userinfor, username, password); //提取用户名和密码 //检测用户名是否已经注册过if (TestDuplicateRigister(username)){SendMessage("N", cli);continue;}//向文件写入新注册的用户名和密码if (!Checktxt()){SendMessage("N", cli);continue;}fstream out("C:\\userform\\userform.txt", ios::app);out << userinfor << endl;out.close();//发送注册成功的回应SendMessage("Y", cli);cout << "注册成功" << endl << "新用户名为:" << username << endl <" + receivername + ":" + message; //设置要打印的消息cout << printmessage << endl;cout << "用户ip:" << address << endl;cout << "用户端口:" << userport << endl;cout << "当前在线人数:" << usertable.size() << endl <= usertable.size() || i < 0) continue;SendMessage("exit", usertable[i].receiver); //向该用户显示器发送退出命令usertable.erase(usertable.begin() + i);printmessage = "(下线消息)" + sendername + "已下线"; //设置要打印的消息sendmessage = printmessage; //设置要转发的消息}//在服务器上打印消息cout << printmessage << endl;cout << "用户ip:" << address << endl;cout << "用户端口:" << userport << endl;cout << "当前在线人数:" << usertable.size() << endl << endl;//向客户端发送消息for (int i = 0; i < usertable.size(); i++)SendMessage(sendmessage, usertable[i].receiver);}}int main(){server x;if (x.Startup() == false)return 0;if (x.SetServerSocket() == false)return 0;x.work();return 0;}

客户端发送器的完整代码

#include#include#include#include#include#include#include#include#include using namespace std;#pragma comment(lib,"ws2_32.lib")#define DEFAULT_PORT 5055#define DATA_BUFFER 1024class client{public:bool Startup();void SetServerAddress();int GeneratePort(); //随机生成显示器端口号bool Getonlinelist(); //获得在线的用户名void work();//发送器的主函数private:WSADATA wsaData;SOCKET sClient; //发送信息和接收信息时使用的套接字struct sockaddr_in ser; //保存服务器的地址int ser_length = sizeof(ser);struct sockaddr_in communication;int communication_length = sizeof(communication);char recv_buf[DATA_BUFFER]; //接收信息的缓冲区int receiver_port;//显示器的端口号vector onlinelist;//保存在线用户的用户名int iSend, iRecv;};bool client::Startup(){if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){cout << "Failed to load Winsock." << endl;return false;}sClient = socket(AF_INET, SOCK_DGRAM, 0);if (sClient == INVALID_SOCKET){cout << "socket()Failed:" << WSAGetLastError() << endl;return false;}return true;}void client::SetServerAddress(){cout <> iptemp;char *ip = new char[iptemp.length() + 1];strcpy(ip, iptemp.c_str());//建立服务器端地址ser.sin_family = AF_INET;ser.sin_port = htons(DEFAULT_PORT);ser.sin_addr.s_addr = inet_addr(ip);}int client::GeneratePort(){srand((unsigned)time(NULL));int x = 1024 + rand() % (5000 - 1024);return x;}bool client::Getonlinelist()//向服务器请求获取好友在线列表{if (onlinelist.size() > 0)onlinelist.clear();char getonlinelist[3] = "PL";iSend = sendto(sClient, getonlinelist, 3, 0, (struct sockaddr*)&ser, ser_length);if (iSend == SOCKET_ERROR){cout << "sendto()Failed:" << WSAGetLastError() << endl;return false;}memset(recv_buf, 0, sizeof(recv_buf));iRecv = recvfrom(sClient, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&communication, &communication_length); ///if (iRecv == SOCKET_ERROR){cout << "recvfrom() Failed" << WSAGetLastError() << endl;return false;}string list(recv_buf);string friendname;for (int i = 0; i < list.length(); i++){if (list[i] == '$')break;else if (list[i] == '#'){onlinelist.push_back(friendname);friendname = "";}elsefriendname = friendname + list[i];}cout << "----------------------------" << endl;cout << "在线好友列表" << endl;for (int i = 0; i < onlinelist.size(); i++)cout << i << ":" << onlinelist[i] << endl;cout << "----------------------------" << endl;return true;}void client::work(){while (true){memset(recv_buf, 0, sizeof(recv_buf));system("cls");cout << "****************************************" << endl;cout << "**" << endl;cout << "* 1.登录2.注册3.退出 *" << endl;cout << "**" << endl;cout << "****************************************" << endl;string choice;getline(cin, choice);if (choice == "1"){system("cls");cout << "请输入用户名:";string username;getline(cin, username);cout << "请输入密码:";string password;getline(cin, password);//产生显示器端口receiver_port = GeneratePort();//将端口号写入文件供显示器程序读取ofstream out("port.txt");out << receiver_port << "\n" << username;out.close();string init_infortemp = "L" + username + "#" + password + "#" + to_string(receiver_port);char *init_infor = new char[init_infortemp.length() + 1];strcpy(init_infor, init_infortemp.c_str());//向服务器验证用户信息iSend = sendto(sClient, init_infor, init_infortemp.length() + 1, 0, (struct sockaddr*)&ser, ser_length);//接收服务器回应的消息iRecv = recvfrom(sClient, recv_buf, sizeof(recv_buf), 0, (SOCKADDR*)&communication, &communication_length);if (iRecv == SOCKET_ERROR){cout << "recvfrom() Failed:" << GetLastError() << endl;cout << "未收到服务器的响应,登录失败,请输入Y返回首页:";string ret;while (getline(cin, ret)){if (ret == "Y")break;cout << "未收到服务器的响应,登录失败,请输入Y返回首页:";}continue;}if (recv_buf[0] == 'Y') //登录成功{system("cls");ShellExecute(NULL, _T("open"), _T("receiver.exe"), NULL, NULL, SW_SHOW); //运行显示器程序}else if (recv_buf[0] == '0'){cout << "未注册用户名,登录失败,请输入Y返回首页:";string ret;while (getline(cin, ret)){if (ret == "Y")break;cout << "未注册用户名,登录失败,请输入Y返回首页:";}continue;}else if (recv_buf[0] == '1'){cout << "密码错误,登录失败,请输入Y返回首页:" << endl;string ret;while (getline(cin, ret)){if (ret == "Y")break;cout << "密码错误,登录失败,请输入Y返回首页:";}continue;}else if (recv_buf[0] == '2'){cout << "重复登录,登录失败,请输入Y返回首页:" << endl;string ret;while (getline(cin, ret)){if (ret == "Y")break;cout << "重复登录,登录失败,请输入Y返回首页:";}continue;}//选择聊天方式while (true){system("cls");cout << "---------------------------------------------------" << endl;cout << " 用户名:" << username << endl << endl;;cout << "1.私聊2.群聊3.退出登录 " << endl << endl;cout << "---------------------------------------------------" << endl;string mode;getline(cin, mode);if (mode == "1")//私聊{system("cls");cout << "私聊模式中,输入return返回上一级" << endl << endl;if (!Getonlinelist())continue; //获取好友在线列表失败cout << "请选择私聊对象的序号" << endl;string choose;getline(cin, choose);if (choose == "return") continue;int i = 0;for (i = 0; i  '9' || choose[i] < '0')break;if (i > index;if (index=onlinelist.size()) continue;while (true) //向该用户循环发送消息,直到输入return退出{system("cls");cout << "正在和" << onlinelist[index] << "私聊中" << ",输入return返回上一级" << endl << endl;string message;getline(cin, message);if (message == "return"){system("cls");break;}message = "PM" + onlinelist[index] + "#" + message;char *buf = new char[message.length() + 1];strcpy(buf, message.c_str());iSend = sendto(sClient, buf, message.length() + 1, 0, (struct sockaddr*)&ser, ser_length);if (iSend == SOCKET_ERROR){cout << "sendto()Failed:" << WSAGetLastError() << endl;break;}delete[]buf;iRecv = recvfrom(sClient, recv_buf, sizeof(recv_buf), 0, (SOCKADDR*)&communication, &communication_length);if (recv_buf[0] == 'Y') continue;else{cout << onlinelist[index] << "已下线" << "输入Y返回主菜单";string ret;while (getline(cin, ret)){if (ret == "Y") break;cout << onlinelist[index] << "已下线" << "输入Y返回主菜单";}break;}}}else if (mode == "2")//群聊{system("cls");while (true){system("cls");cout << "群聊模式,输入return返回上一级" << endl << endl;string message;getline(cin, message);if (message == "return"){system("cls");break;}message = "G" + message;char *buf = new char[message.length() + 1];strcpy(buf, message.c_str());iSend = sendto(sClient, buf, message.length() + 1, 0, (struct sockaddr*)&ser, ser_length);delete[]buf;if (iSend == SOCKET_ERROR){cout << "sendto()Failed:" << WSAGetLastError() << endl;break;}}continue;}else if (mode == "3") //退出登录{char buf[] = "exit";iSend = sendto(sClient, buf, sizeof(buf), 0, (struct sockaddr*)&ser, ser_length);break;}elsecontinue;}}else if (choice == "2"){system("cls");cout << "请设置用户名:";string username;getline(cin, username);cout << "请设置登录密码:";string password;getline(cin, password);string init_infortemp = "R" + username + "#" + password;char *init_infor = new char[init_infortemp.length() + 1];strcpy(init_infor, init_infortemp.c_str());//向服务器发送注册用户信息iSend = sendto(sClient, init_infor, init_infortemp.length() + 1, 0, (struct sockaddr*)&ser, ser_length);//接收服务器回应的消息iRecv = recvfrom(sClient, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&communication, &communication_length);if (recv_buf[0] == 'Y'){cout << "注册成功" << endl;continue;}else{cout << "用户名已存在,注册失败,请输入Y返回首页:" << endl;string ret;while (getline(cin, ret)){if (ret == "Y")break;cout << "用户名已存在,注册失败,请输入Y返回首页:";}continue;}}else if (choice == "3"){closesocket(sClient);WSACleanup;return;}elsecontinue;}}int main(){client x;if (x.Startup() == false)return 0;x.SetServerAddress();x.work();}

客户端接收器的完整代码

#include#include#include#include#include#pragma comment(lib,"ws2_32.lib")using namespace std;#define DEFAULT_SPORT 5055#define DEFAULT_CPORT 5056#define BUFFER_LENGTH 1024void main(){WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){cout << "Failed to load Winsock." << endl;return;}//建立显示器端地址struct sockaddr_in receiver;//读取分配好的端口ifstream in("port.txt");string receiver_port;string username;getline(in, receiver_port);getline(in, username);in.close();remove("port.txt");int receiver_port_int = atoi(receiver_port.c_str());receiver.sin_family = AF_INET;receiver.sin_port = htons(receiver_port_int);//htons()函数把一个双字节主机字节顺序的数转换为网络字节顺序的数receiver.sin_addr.s_addr = htonl(INADDR_ANY);//htonl()函数把一个主机字节顺序的数转换为网络字节顺序的数 SOCKET rSocket = socket(AF_INET, SOCK_DGRAM, 0);if (rSocket == INVALID_SOCKET){cout << "socket()Failed:" << WSAGetLastError() << endl;return;}if (bind(rSocket, (LPSOCKADDR)&receiver, sizeof(receiver)) == SOCKET_ERROR){cout << "bind()Failed:" << WSAGetLastError() << endl;return;}char recv_buf[BUFFER_LENGTH];//接收数据的缓冲区memset(recv_buf, 0, sizeof(recv_buf)); //初始化接收缓冲区struct sockaddr_in ser;//客户端地址int ser_length = sizeof(ser);//客户端地址长度cout << "----------------------------------------" << endl << endl;cout << " 显示器---" << username << endl << endl << endl;cout << "----------------------------------------" << endl << endl;while (true) //进入一个无限循环,进行数据接收和发送{int iRecv = recvfrom(rSocket, recv_buf, BUFFER_LENGTH, 0, (SOCKADDR*)&ser, &ser_length);string transmessage(recv_buf);if (iRecv == SOCKET_ERROR){cout << "recvfrom()Failed:" << WSAGetLastError() << endl;break;}else if (transmessage == "exit") break;elsecout << transmessage << endl;}closesocket(rSocket);WSACleanup();}