├── README.md ├── UDP实现可靠传输3-1 ├── 可执行文件 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ └── main.exe └── 源代码 │ ├── UDP.cpp │ ├── UDP.h │ └── main.cpp ├── UDP实现可靠传输3-2+3-3 ├── 可执行文件 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── c_recv_1.jpg │ ├── helloworld.txt │ └── main.exe └── 源代码 │ ├── UDP.cpp │ ├── UDP.h │ └── main.cpp ├── UDP实现可靠传输3-4 └── 实验报告.pdf ├── Web服务器交互分析 ├── Web页面代码 │ ├── .idea │ │ ├── .gitignore │ │ ├── inspectionProfiles │ │ │ ├── Project_Default.xml │ │ │ └── profiles_settings.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ └── 计算机网络实验二:配置Web服务器.iml │ ├── __pycache__ │ │ └── app.cpython-39.pyc │ ├── app.py │ ├── static │ │ └── computer-network_aaaa.jpg │ └── templates │ │ └── web.html └── Wireshark捕获.pcapng └── 聊天室 ├── 双人聊天 ├── Double-Server.cpp └── Double_Client.cpp └── 多人群聊 ├── Mul-Client.cpp └── Mul-Server.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Computer-Networks 2 | NKU-COSC0010-计算机网络 3 | 4 | 以下实验均分99,如果需要实验报告欢迎私信我 5 | 6 | 7 | 8 | ### 一, 聊天室 9 | 10 | 1. #### 功能: 11 | 12 | + 双人聊天、多人群聊(多线程) 13 | 14 | + 群发或定点转发 15 | 16 | + 合理性检验 17 | 18 | 19 | 20 | ### 二. UDP实现可靠性传输 21 | 22 | 1. ### 实验3-1 23 | 24 | + #### 基础功能 25 | 26 | + ##### 建立连接: 27 | 28 | 实现类似于 TCP 的三次握手、四次挥手过程 29 | 30 | + ##### 差错检测: 31 | 32 | 利用校验和进行差错检测,发送端将数据报看成 16 位整数序列,将整个数据报相加然后取反写入校验和域段,接收端将数据报用 0 补齐为 16 位整数倍,然后相加求和,如果计算结果为全 1,没有检测到错误;否则说明数据报存在差错。 33 | 34 | + ##### 流量控制(停等机制): 35 | 36 | 采用停等协议,发送端发送一个分组,然后等待接收端响应 37 | 38 | + ##### 日志输出: 39 | 40 | 打印出三次握手四次挥手过程、序列号、确认序列号、数据大小、时延、吞吐率。 41 | 42 | + ##### 超时重传 43 | 44 | 采用 rdt3.0 机制,由于通道既可能有差错,又可能有丢失,所以我们考虑利用rdt3.0 机制实现可靠数据传输。 45 | 46 | + #### 附加功能 47 | 48 | + ##### MSS协商 49 | 50 | 双方将会协商MSS,选择双⽅需求的最小MSS作为通信MSS。 51 | 52 | + ##### 多线程 53 | 54 | 为了兼容后期拥塞控制的实验,本次代码在设计上采⽤多线程控制,由发送线程和接收线程互相配合完成发送或者接收的任务。 55 | 56 | + ##### 异常检测 57 | 58 | 1. 断开方式与TCP基本相同,为了保证通信状态正常,在没有任何信息需要发送时,双⽅也会在固定的时间内发送⼀个小数据包,以检测连接状态和报告⾃身情况。当数据包出现10次连续丢失时,双方将认为通信异常,自动启动断开程序。 59 | 60 | 61 | 62 | 2. ### 实验3-2 + 3-3[补充于3-1] 63 | 64 | + **拥塞控制**:在实验 3-2 的基础上,利用 RENO 算法实现拥塞控制,实现了超时检测和三次重复 ACK 检测。 65 | 66 | + **流量控制**:在实验 3-1 的基础上,将停等机制改成基于滑动窗口的流量控制机制, 采用 GBN方法。 67 | 68 | + **快速重传**:接收到 3 个重复 ACK 时快速重传收到 ACK 序列号所指示的报文段。 69 | 70 | 71 | 72 | 3. ### 实验3-4 73 | 74 | + 停等机制与滑动窗口机制性能对比 75 | + 滑动窗口机制中不同窗口大小对性能的影响 76 | + 有拥塞控制和无拥塞控制的性能比较 77 | -------------------------------------------------------------------------------- /UDP实现可靠传输3-1/可执行文件/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-1/可执行文件/1.jpg -------------------------------------------------------------------------------- /UDP实现可靠传输3-1/可执行文件/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-1/可执行文件/2.jpg -------------------------------------------------------------------------------- /UDP实现可靠传输3-1/可执行文件/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-1/可执行文件/3.jpg -------------------------------------------------------------------------------- /UDP实现可靠传输3-1/可执行文件/main.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-1/可执行文件/main.exe -------------------------------------------------------------------------------- /UDP实现可靠传输3-1/源代码/UDP.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-1/源代码/UDP.cpp -------------------------------------------------------------------------------- /UDP实现可靠传输3-1/源代码/UDP.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-1/源代码/UDP.h -------------------------------------------------------------------------------- /UDP实现可靠传输3-1/源代码/main.cpp: -------------------------------------------------------------------------------- 1 | #include "UDP.h" 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | //int main() 7 | //{ 8 | // cout << "请选择您想传输的文件:" << endl; 9 | // cout << "1: 1.jpg 2:2.jpg 3:3.jpg 4:4.jpg" << endl; 10 | // int num; 11 | // string TEST_FILE, TEST_FILE_REV; 12 | // cin >> num; 13 | // switch (num) 14 | // { 15 | // case 1: 16 | // TEST_FILE = "1.jpg"; 17 | // case 2: 18 | // TEST_FILE = "2.jpg"; 19 | // case 3: 20 | // TEST_FILE = "3.jpg"; 21 | // case 4: 22 | // TEST_FILE = "helloword.txt"; 23 | // } 24 | // TEST_FILE_REV = "recv_" + TEST_FILE; //接收文件名 25 | // 26 | // 27 | // cout << "请选择您的传输类型:" << endl; 28 | // cout << "1: 发送 2:接收" << endl; 29 | // cin >> num; 30 | // switch (num) 31 | // { 32 | // case 1: 33 | // { 34 | // // 发送端 35 | // // 127.0.0.1代表客户端IP地址,4000为客户端端口号,5000为服务器端本机端口号 36 | // UDP sock_send("127.0.0.1", 4000, 5000); 37 | // sock_send.accept(); // 三次握手建立连接 38 | // //打开文件读取 39 | // ifstream file(TEST_FILE, ios::binary); 40 | // // 读指针设置为文件结尾,获取当前位置即为文件大小size 41 | // file.seekg(0, ios::end); 42 | // int size = file.tellg(); 43 | // char* buf = new char[size]; 44 | // // 读指针设置为文件开始,读取所有文件数据至缓冲区 45 | // file.seekg(0, ios::beg); 46 | // file.read(buf, size); 47 | // // 将数据放入发送缓冲区,并开始计时 48 | // string abc(buf, size); 49 | // time_t time_send = time(NULL); 50 | // sock_send.send(abc); 51 | // delete[] buf; 52 | // 53 | // // 当发送缓冲区为空时关闭线程,结束计时 54 | // sock_send.close(); 55 | // time_send = time(NULL) - time_send; 56 | // cout << "Time: " << time_send << "s" << endl; // 时间 57 | // cout << "Data: " << abc.length() << " Bytes" << endl; // 数据大小 58 | // cout << "Rate: " << abc.length() / time_send << endl; // 吞吐率 59 | // } 60 | // case 2: 61 | // { 62 | // // 接收端 63 | // UDP sock_recv("127.0.0.1", 5000, 4000); 64 | // sock_recv.connect(); // 接收端建立连接 65 | // 66 | // // 接收端 67 | // time_t time_red = time(NULL); 68 | // // 从接收缓冲区读取数据 69 | // string cont = sock_recv.recv(); 70 | // time_red = time(NULL) - time_red; 71 | // cout << "Time: " << time_red << "s" << endl; 72 | // cout << "Data: " << cont.length() << " Bytes" << endl; 73 | // cout << "Rate: " << cont.length() / time_red << endl; 74 | // ofstream file2("c_" + TEST_FILE_REV, ios::binary); 75 | // file2.write(cont.data(), cont.length()); 76 | // } 77 | // } 78 | //} 79 | 80 | int main(int argc, const char* argv[]) { 81 | string TEST_FILE; 82 | string TEST_FILE_REV; 83 | if (argc > 1) { 84 | TEST_FILE = argv[1]; // 读取文件名 85 | TEST_FILE_REV = "Recv_" + TEST_FILE; //接收文件名 86 | } 87 | else { 88 | // 提示找不到文件 89 | cout << "No file" << endl; 90 | return 0; 91 | } 92 | // 当输入第三个参数为-s时代表发送数据 93 | if (argc > 2 && strcmp(argv[2], "-s") == 0) { 94 | // 127.0.0.1代表客户端IP地址,4000为客户端端口号,5000为服务器端本机端口号 95 | UDP sock("127.0.0.1", 4000, 5000); 96 | sock.accept(); // 三次握手建立连接 97 | // 发送端 98 | //打开文件读取 99 | ifstream file(TEST_FILE, ios::binary); 100 | // 读指针设置为文件结尾,获取当前位置即为文件大小size 101 | file.seekg(0, ios::end); 102 | int size = file.tellg(); 103 | char* buf = new char[size]; 104 | // 读指针设置为文件开始,读取所有文件数据至缓冲区 105 | file.seekg(0, ios::beg); 106 | file.read(buf, size); 107 | // 将数据放入发送缓冲区,并开始计时 108 | string abc(buf, size); 109 | time_t time_red = time(NULL); 110 | sock.send(abc); 111 | delete[] buf; 112 | 113 | // 当发送缓冲区为空时关闭线程,结束计时 114 | sock.close(); 115 | time_red = time(NULL) - time_red; 116 | cout << "Time: " << time_red << "s" << endl; // 时间 117 | cout << "Data: " << abc.length() << " Bytes" << endl; // 数据大小 118 | cout << "Rate: " << abc.length() / time_red << "Bytes/s" << endl; //吞吐率 119 | } 120 | else { 121 | UDP sock("127.0.0.1", 5000, 4000); 122 | sock.connect(); // 接收端建立连接 123 | 124 | // 接收端 125 | time_t time_red = time(NULL); 126 | // 从接收缓冲区读取数据 127 | string cont = sock.recv(); 128 | time_red = time(NULL) - time_red; 129 | cout << "Time: " << time_red << "s" << endl; 130 | cout << "Data: " << cont.length() << " Bytes" << endl; 131 | cout << "Rate: " << cont.length() / time_red << "Bytes/s" << endl; //吞吐率 132 | ofstream file2(TEST_FILE_REV, ios::binary); 133 | file2.write(cont.data(), cont.length()); 134 | } 135 | } -------------------------------------------------------------------------------- /UDP实现可靠传输3-2+3-3/可执行文件/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-2+3-3/可执行文件/1.jpg -------------------------------------------------------------------------------- /UDP实现可靠传输3-2+3-3/可执行文件/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-2+3-3/可执行文件/2.jpg -------------------------------------------------------------------------------- /UDP实现可靠传输3-2+3-3/可执行文件/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-2+3-3/可执行文件/3.jpg -------------------------------------------------------------------------------- /UDP实现可靠传输3-2+3-3/可执行文件/c_recv_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-2+3-3/可执行文件/c_recv_1.jpg -------------------------------------------------------------------------------- /UDP实现可靠传输3-2+3-3/可执行文件/main.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-2+3-3/可执行文件/main.exe -------------------------------------------------------------------------------- /UDP实现可靠传输3-2+3-3/源代码/UDP.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-2+3-3/源代码/UDP.cpp -------------------------------------------------------------------------------- /UDP实现可靠传输3-2+3-3/源代码/UDP.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-2+3-3/源代码/UDP.h -------------------------------------------------------------------------------- /UDP实现可靠传输3-2+3-3/源代码/main.cpp: -------------------------------------------------------------------------------- 1 | #include "UDP.h" 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | 8 | int main(int argc, const char* argv[]) { 9 | 10 | string TEST_FILE; 11 | string TEST_FILE_REV; 12 | if (argc > 1) { 13 | TEST_FILE = argv[1]; 14 | TEST_FILE_REV = "recv_" + TEST_FILE; 15 | } 16 | else { 17 | cout << "No file" << endl; 18 | return 0; 19 | } 20 | if (argc > 2 && strcmp(argv[2], "-s") == 0) { 21 | UDP sock("127.0.0.1", 4000, 5000); 22 | sock.accept(); // 三次握手建立连接 23 | 24 | // 发送端 25 | ifstream file(TEST_FILE, ios::binary); 26 | 27 | // 读指针设置为文件结尾,获取当前位置即为文件大小size 28 | file.seekg(0, ios::end); 29 | size_t size = file.tellg(); 30 | char* buf = new char[size]; 31 | 32 | // 读指针设置为文件开始,读取所有文件数据至缓冲区 33 | file.seekg(0, ios::beg); 34 | file.read(buf, size); 35 | 36 | // 将数据放入发送缓冲区,并开始计时 37 | string abc(buf, size); 38 | time_t time_red = time(NULL); 39 | sock.send(abc); 40 | delete[] buf; 41 | 42 | // 当发送缓冲区为空时关闭线程,结束计时 43 | sock.close(); 44 | 45 | time_red = time(NULL) - time_red; 46 | cout << "Time: " << time_red << "s" << endl; // 时间 47 | cout << "Data: " << abc.length() << " Bytes" << endl; // 数据大小 48 | cout << "Rate: " << abc.length() / time_red << "Bytes/s" << endl; // 吞吐率 49 | } 50 | else { 51 | UDP sock("127.0.0.1", 5000, 4000); 52 | sock.connect(); // 接收端建立连接 53 | // 接收端 54 | time_t time_red = time(NULL); 55 | string cont = sock.recv(); 56 | 57 | time_red = time(NULL) - time_red; 58 | cout << "Time: " << time_red << "s" << endl; 59 | cout << "Data: " << cont.length() << " Bytes" << endl; 60 | cout << "Rate: " << cont.length() / time_red <<"Bytes/s"<< endl; 61 | ofstream file2("c_" + TEST_FILE_REV, ios::binary); 62 | file2.write(cont.data(), cont.length()); 63 | } 64 | } -------------------------------------------------------------------------------- /UDP实现可靠传输3-4/实验报告.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/UDP实现可靠传输3-4/实验报告.pdf -------------------------------------------------------------------------------- /Web服务器交互分析/Web页面代码/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | # 基于编辑器的 HTTP 客户端请求 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /Web服务器交互分析/Web页面代码/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 26 | -------------------------------------------------------------------------------- /Web服务器交互分析/Web页面代码/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /Web服务器交互分析/Web页面代码/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Web服务器交互分析/Web页面代码/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Web服务器交互分析/Web页面代码/.idea/计算机网络实验二:配置Web服务器.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /Web服务器交互分析/Web页面代码/__pycache__/app.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/Web服务器交互分析/Web页面代码/__pycache__/app.cpython-39.pyc -------------------------------------------------------------------------------- /Web服务器交互分析/Web页面代码/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | 3 | # 创建Flask类实例app 4 | app = Flask(__name__) 5 | 6 | # 通过装饰器设置函数URLs访问路径 7 | @app.route('/') 8 | 9 | 10 | # 定义设置网站首页的处理函数 11 | def hello_world(): 12 | return render_template("web.html") 13 | 14 | if __name__ == '__main__': 15 | app.run() 16 | -------------------------------------------------------------------------------- /Web服务器交互分析/Web页面代码/static/computer-network_aaaa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/Web服务器交互分析/Web页面代码/static/computer-network_aaaa.jpg -------------------------------------------------------------------------------- /Web服务器交互分析/Web页面代码/templates/web.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 配置Web服务器 6 | 7 | 8 |

基本信息

> 9 |

姓名:聂志强

10 |

学号:2012307

11 |

专业:信息安全

12 |

LOGO

> 13 |

14 | 15 | -------------------------------------------------------------------------------- /Web服务器交互分析/Wireshark捕获.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Time-nie/Computer-Networks/72ddab54ac02d95d8f68638c64272f9c2754566e/Web服务器交互分析/Wireshark捕获.pcapng -------------------------------------------------------------------------------- /聊天室/双人聊天/Double-Server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | //加载ws2_32.lib库 7 | #pragma comment(lib,"ws2_32.lib") 8 | time_t t; 9 | 10 | using namespace std; 11 | 12 | int main() 13 | { 14 | //定义获得可用socket的详细信息的变量, 存放被WSAStartup函数调用后返回的Windows Sockets数据的数据结构 15 | WSADATA wsaData; 16 | WSAStartup(MAKEWORD(2, 2), &wsaData);//声明使用socket2.2版本 17 | 18 | 19 | //创建套接字Socket,并绑定到一个特定的传输层服务,IP地址类型为AF_INET(IPV-4 32位),服务类型为流式(SOCK_STREAM),Protocol(协议)为0代表系统自动选则 20 | SOCKET ServerSocket; 21 | ServerSocket = socket(AF_INET, SOCK_STREAM, 0); //ipv4的地址类型;流结构的服务类型;Protocol(协议)为0代表系统自动选则 22 | 23 | if (ServerSocket == INVALID_SOCKET) 24 | { 25 | cout << "套接字创建失败,请通过:" << WSAGetLastError() << "获取错误详情" << endl; 26 | return -1; 27 | } 28 | 29 | //通过bind绑定本地地址到socket上 30 | SOCKADDR_IN ServerAddr; 31 | USHORT uPort = 2022; 32 | ServerAddr.sin_family = AF_INET; 33 | ServerAddr.sin_port = htons(uPort); 34 | //宏INADDR_ANY转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的所有IP 35 | ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); 36 | 37 | 38 | //将本地地址绑定到指定的Socket 39 | if (SOCKET_ERROR == bind(ServerSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))) 40 | { 41 | cout << "bind 失败,请通过" << WSAGetLastError() << "获取错误详情" << endl; 42 | closesocket(ServerSocket); 43 | return -1; 44 | } 45 | // time函数获取从1970年1月1日0时0分0秒到此时的秒数 46 | time(&t); 47 | char str[26]; 48 | //将时间格式化 49 | strftime(str, 20, "%Y-%m-%d %X", localtime(&t)); 50 | cout << str << endl; 51 | //界面初始化,提示服务器输入名字 52 | cout << "请输入服务器端用户名" << endl; 53 | char serverName[10] = { 0 }; 54 | cin >> serverName; 55 | 56 | 57 | cout << "开启监听,请等待其他客户端连接..." << endl; 58 | 59 | // 绑定完成后开始listen,这里设置的允许等待连接的最大队列为1 60 | // 使socket进入监听状态,监听远程连接是否到来 61 | if (listen(ServerSocket, 1)!=0) 62 | { 63 | cout << "监听失败,请通过" << WSAGetLastError() <<"获取错误详情"<< endl; 64 | closesocket(ServerSocket); 65 | WSACleanup(); 66 | return -1; 67 | } 68 | 69 | 70 | SOCKET Conn_new_Socket; 71 | SOCKADDR_IN Conn_new_Addr; 72 | int iClientAddrLen = sizeof(Conn_new_Addr); 73 | 74 | // accept()阻塞进程直到有客户端连接,接受一个特定socket请求等待队列中的连接请求 75 | //Conn_new_Socket的信息不用bind,因为它会随着serveraccept的地址传过来 76 | // accept参数:socket描述符,保存地址,保存地址长度,返回新连接的socket描述符 77 | Conn_new_Socket = accept(ServerSocket, (SOCKADDR*)&Conn_new_Addr, &iClientAddrLen); 78 | 79 | if (Conn_new_Socket == INVALID_SOCKET) 80 | { 81 | cout << "accept接受请求失败,请通过" << WSAGetLastError() <<"获取错误详情"<< endl; 82 | closesocket(ServerSocket); 83 | WSACleanup(); 84 | return -1; 85 | } 86 | 87 | //界面提示,显示连接者的信息 88 | cout << "已经与成功建立连接,如果您想结束结束对话请输入:exit" << endl; 89 | cout << "客户端信息:" << endl; 90 | cout << "IP: " << inet_ntoa(Conn_new_Addr.sin_addr) << " " << " 端口号: " << htons(Conn_new_Addr.sin_port) << endl << endl; 91 | 92 | 93 | char clientName[32] = { 0 }; // clientName保存客户端用户名 94 | char buffer[4096] = { 0 }; 95 | int RecvLen = 0; //实际收到的字节数 96 | int SendLen = 0; //实际发送的字节数 97 | 98 | // 把serverName发给对方 99 | // send函数向远程socket发送数据,返回实际发送的字节数,已经建立TCP连接,不需要指定对方地址,直接将数据放入TCP连接中 100 | // 参数:socket描述符,buf发送数据缓存区,len发送缓冲区长度,flags-对调用的处理方式,如OOB等 101 | if (SOCKET_ERROR == send(Conn_new_Socket, serverName, strlen(serverName), 0)) 102 | { 103 | cout << "send发送失败,请通过" << WSAGetLastError() <<"获取详情"<< endl; 104 | closesocket(Conn_new_Socket); 105 | closesocket(ServerSocket); 106 | WSACleanup(); 107 | return -1; 108 | } 109 | 110 | //接收对方发过来的信息 111 | if (SOCKET_ERROR == recv(Conn_new_Socket, clientName, sizeof(clientName), 0)) 112 | { 113 | cout << "recv失败,请通过" << WSAGetLastError() <<"获取详情"<< endl; 114 | closesocket(Conn_new_Socket); 115 | closesocket(ServerSocket); 116 | WSACleanup(); 117 | return -1; 118 | } 119 | 120 | //下面的逻辑就是先显示从client方收到的消息,判断是否是结束字符; 121 | //而后输入server自己想发的消息,传到client去; 122 | //任意一方如果发出结束符,那么等对方回复一条消息后,两边都会结束对话。 123 | while (true) 124 | { 125 | // 接收客户端信息 126 | memset(buffer, 0, sizeof(buffer)); 127 | if (SOCKET_ERROR == recv(Conn_new_Socket, buffer, sizeof(buffer), 0)) 128 | { 129 | cout << "recv失败,请通过" << WSAGetLastError() << "获取详情" << endl; 130 | closesocket(Conn_new_Socket); 131 | closesocket(ServerSocket); 132 | WSACleanup(); 133 | return -1; 134 | } 135 | if (strcmp(buffer, "exit") == 0) 136 | { 137 | // time函数获取从1970年1月1日0时0分0秒到此时的秒数 138 | time(&t); 139 | char str[26]; 140 | //将时间格式化 141 | strftime(str, 20, "%Y-%m-%d %X", localtime(&t)); 142 | cout << str << endl; 143 | cout << clientName << ":"; 144 | cout << buffer << endl; 145 | memset(buffer, 0, sizeof(buffer)); 146 | cout << serverName << ":"; 147 | cin >> buffer; 148 | SendLen = send(Conn_new_Socket, buffer, strlen(buffer), 0); 149 | break; 150 | } 151 | // time函数获取从1970年1月1日0时0分0秒到此时的秒数 152 | time(&t); 153 | char str[26]; 154 | //将时间格式化 155 | strftime(str, 20, "%Y-%m-%d %X", localtime(&t)); 156 | cout << str << endl; 157 | cout << '['<> buffer; 170 | if (strcmp(buffer, "exit") == 0) 171 | { 172 | if (SOCKET_ERROR == send(Conn_new_Socket, buffer, strlen(buffer), 0)) 173 | { 174 | cout << "send失败,请通过" << WSAGetLastError() << "获取详情" << endl; 175 | closesocket(Conn_new_Socket); 176 | closesocket(ServerSocket); 177 | WSACleanup(); 178 | return -1; 179 | } 180 | cout << clientName << ":"; 181 | memset(buffer, 0, sizeof(buffer)); 182 | RecvLen = recv(Conn_new_Socket, buffer, sizeof(buffer), 0); 183 | cout << buffer << endl; 184 | break; 185 | } 186 | if (SOCKET_ERROR == send(Conn_new_Socket, buffer, strlen(buffer), 0)) 187 | { 188 | cout << "send发送失败,请通过" << WSAGetLastError() << "获取详情" << endl; 189 | closesocket(Conn_new_Socket); 190 | closesocket(ServerSocket); 191 | WSACleanup(); 192 | return -1; 193 | } 194 | } 195 | //关闭socket 196 | closesocket(Conn_new_Socket); 197 | closesocket(ServerSocket); 198 | // 结束使用socket,释放Socket DLL资源 199 | WSACleanup(); 200 | //system("pause"); 201 | return 0; 202 | } 203 | 204 | 205 | -------------------------------------------------------------------------------- /聊天室/双人聊天/Double_Client.cpp: -------------------------------------------------------------------------------- 1 | // 双人聊天——客户端 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | # define IP "127.0.0.1" 9 | #pragma comment(lib,"ws2_32.lib") 10 | using namespace std; 11 | //日历时间是通过time_t数据类型来表示的,用time_t表示的时间(日历时间)是从一个时间点(例如:1970年1月1日0时0分0秒)到此时的秒数。time_t是一个长整型数: 12 | time_t t; 13 | 14 | int main() 15 | { 16 | WSADATA wsaData; 17 | WSAStartup(MAKEWORD(2, 2), &wsaData);//声明使用socket2.2版本 18 | 19 | //创建套接字,IP地址类型为AF_INET(IPV-4 32位),服务类型为流式(SOCK_STREAM),Protocol(协议)为0代表系统自动选则 20 | SOCKET ClientSocket; 21 | ClientSocket = socket(AF_INET, SOCK_STREAM, 0); 22 | if (ClientSocket == INVALID_SOCKET) 23 | { 24 | cout << "套接字创建失败,请通过:" << WSAGetLastError() << "获取错误详情"<< endl; 25 | return -1; 26 | } 27 | 28 | // time函数获取从1970年1月1日0时0分0秒到此时的秒数 29 | time(&t); 30 | char str[26]; 31 | //将时间格式化 32 | strftime(str, 20, "%Y-%m-%d %X", localtime(&t)); 33 | cout << str << endl; 34 | char clientName[32] = { 0 }; 35 | cout << "请输入你的昵称: " << endl; 36 | cin >> clientName; 37 | 38 | //设定所连接服务器地址 39 | SOCKADDR_IN ServerAddr; 40 | USHORT uPort = 2022; 41 | ServerAddr.sin_family = AF_INET; //指定IP地址类型(IPV-4 32位) 42 | ServerAddr.sin_port = htons(uPort); //htons将主机序转网络序 43 | ServerAddr.sin_addr.S_un.S_addr = inet_addr(IP); 44 | 45 | 46 | cout << "开始连接......" << endl; 47 | //把自己的socket与远端连接: 48 | if (SOCKET_ERROR == connect(ClientSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))) 49 | { 50 | cout << "连接失败,请通过" << WSAGetLastError() << "获取详情" << endl; 51 | closesocket(ClientSocket); 52 | WSACleanup(); 53 | return -1; 54 | } 55 | 56 | cout << "成功连接至服务器端,如果您想断开连接请输入 exit " << endl; 57 | cout << "服务器端信息:" << endl; 58 | cout << "IP : " << inet_ntoa(ServerAddr.sin_addr) << " " << "端口号 : " << htons(ServerAddr.sin_port) << endl << endl; 59 | 60 | //下面是对收发消息的存储和显示 61 | char buffer[4096] = { 0 }; 62 | char serverName[32] = { 0 }; 63 | int RecvLen = 0; //实际收到的字节数 64 | int SendLen = 0; //实际发送的字节数 65 | 66 | //把自己的名字发过去 67 | if (SOCKET_ERROR == send(ClientSocket, clientName, strlen(clientName), 0)) 68 | { 69 | cout << "send发送失败,请通过" << WSAGetLastError() <<"获取详情"<< endl; 70 | closesocket(ClientSocket); 71 | WSACleanup(); 72 | return -1; 73 | } 74 | 75 | //接收对方的名字,存进serverName 76 | //双方无论谁先发送结束字符,在等到对方回复一条消息后,双方都会结束。 77 | if (SOCKET_ERROR == recv(ClientSocket, serverName, sizeof(serverName), 0)) 78 | { 79 | cout << "recv失败,请通过" << WSAGetLastError()<< "获取详情" << endl; 80 | closesocket(ClientSocket); 81 | WSACleanup(); 82 | return -1; 83 | } 84 | 85 | while (true) 86 | { 87 | // time函数获取从1970年1月1日0时0分0秒到此时的秒数 88 | time(&t); 89 | //将时间格式化 90 | strftime(str, 20, "%Y-%m-%d %X", localtime(&t)); 91 | cout << str << endl; 92 | memset(buffer, 0, sizeof(buffer)); 93 | 94 | cout << '[' <> buffer; 96 | if (strcmp(buffer ,"exit")==0) 97 | { 98 | if (SOCKET_ERROR == send(ClientSocket, buffer, strlen(buffer), 0)) 99 | { 100 | cout << "send发送失败,请通过" << WSAGetLastError() <<"获取详情"<< endl; 101 | closesocket(ClientSocket); 102 | WSACleanup(); 103 | return -1; 104 | } 105 | // time函数获取从1970年1月1日0时0分0秒到此时的秒数 106 | time(&t); 107 | //将时间格式化 108 | strftime(str, 20, "%Y-%m-%d %X", localtime(&t)); 109 | cout << str << endl; 110 | cout <<'['<< serverName << "] :"; 111 | memset(buffer, 0, sizeof(buffer)); 112 | recv(ClientSocket, buffer, sizeof(buffer), 0); 113 | cout << buffer << endl; 114 | break; 115 | } 116 | if (SOCKET_ERROR == send(ClientSocket, buffer, strlen(buffer), 0)) 117 | { 118 | cout << "send发送失败,请通过" << WSAGetLastError() <<"获取详情"<< endl; 119 | closesocket(ClientSocket); 120 | WSACleanup(); 121 | return -1; 122 | } 123 | 124 | memset(buffer, 0, sizeof(buffer)); 125 | 126 | // time函数获取从1970年1月1日0时0分0秒到此时的秒数 127 | time(&t); 128 | //将时间格式化 129 | strftime(str, 20, "%Y-%m-%d %X", localtime(&t)); 130 | cout << str << endl; 131 | cout << '[' << serverName << "] :"; 132 | 133 | if (SOCKET_ERROR == recv(ClientSocket, buffer, sizeof(buffer), 0)) 134 | { 135 | cout << "recv接收失败,请通过" << WSAGetLastError() <<"了解详情"<< endl; 136 | closesocket(ClientSocket); 137 | WSACleanup(); 138 | return -1; 139 | } 140 | if (strcmp(buffer, "exit") == 0) 141 | { 142 | cout << buffer << endl; 143 | memset(buffer, 0, sizeof(buffer)); 144 | cout <<'['<< clientName << "] :"; 145 | cin >> buffer; 146 | send(ClientSocket, buffer, strlen(buffer), 0); 147 | break; 148 | } 149 | cout << buffer << endl; 150 | } 151 | closesocket(ClientSocket); 152 | WSACleanup(); 153 | } -------------------------------------------------------------------------------- /聊天室/多人群聊/Mul-Client.cpp: -------------------------------------------------------------------------------- 1 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 2 | #define _CRT_SECURE_NO_WARNINGS 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #pragma comment(lib,"ws2_32.lib") 13 | 14 | # define IP "127.0.0.1" 15 | using namespace std; 16 | 17 | char userName[16] = { 0 }; 18 | boolean isPrint = false; // 判断是否要在客户端打印名字 19 | 20 | //日历时间是通过time_t数据类型来表示的,用time_t表示的时间(日历时间)是从一个时间点(例如:1970年1月1日0时0分0秒)到此时的秒数。time_t是一个长整型数: 21 | time_t t; 22 | char str[26]; 23 | 24 | //接收线程 25 | DWORD WINAPI handlerRequest(void* param) 26 | { 27 | char bufferRecv[128] = { 0 }; 28 | // 如果接收正确,则一直处于接收状态 29 | while (true) 30 | { 31 | // 等待并接收消息 32 | if (recv(*(SOCKET*)param, bufferRecv, sizeof(bufferRecv), 0) == SOCKET_ERROR) 33 | break; 34 | if (strlen(bufferRecv) != 0) 35 | { 36 | //'\b'光标迁移 37 | // 坑!一定+2且带等号,有:和空格 38 | for (int i = 0; i <= strlen(userName) + 40; i++) 39 | cout << "\b"; 40 | // 打印时间 41 | time(&t); 42 | strftime(str, 20, "%Y-%m-%d %X", localtime(&t)); 43 | cout << '(' << str << ") "; 44 | // 发送源的名字+数据内容 45 | cout << bufferRecv << endl; 46 | ////因为这是在用户的send态时,把本来打印出来的userName给退回去了,所以收到以后需要再把userName打印出来 47 | cout << '(' << str << ") '[' "<< userName << "] : "; 48 | } 49 | } 50 | return 0; 51 | } 52 | 53 | int main() 54 | { 55 | WSADATA wsaData = { 0 };//存放套接字信息 56 | SOCKET ClientSocket = INVALID_SOCKET;//客户端套接字 57 | SOCKADDR_IN ServerAddr = { 0 };//服务端地址 58 | USHORT uPort = 10000;//服务端端口 59 | 60 | //定义获得可用socket的详细信息的变量, 存放被WSAStartup函数调用后返回的Windows Sockets数据的数据结构 61 | if (WSAStartup(MAKEWORD(2, 2), &wsaData)) 62 | { 63 | cout << "[System] WSAStartup创建失败,请通过" << WSAGetLastError() << "获取详情" << endl; 64 | return -1; 65 | } 66 | 67 | //创建套接字 68 | ClientSocket = socket(AF_INET, SOCK_STREAM, 0); 69 | if (ClientSocket == INVALID_SOCKET) 70 | { 71 | cout << "[System] Socket创建错误,请通过" << WSAGetLastError() << "获取详情" << endl; 72 | return -1; 73 | } 74 | 75 | //设置服务器地址 76 | ServerAddr.sin_family = AF_INET; 77 | ServerAddr.sin_port = htons(uPort);//客户端端口号 78 | ServerAddr.sin_addr.S_un.S_addr = inet_addr(IP);//客户端IP地址 79 | 80 | cout << "[System] 正在连接..." << endl; 81 | 82 | //连接服务器 83 | if (SOCKET_ERROR == connect(ClientSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))) 84 | { 85 | cout << "[System] Connect连接错误,请通过" << WSAGetLastError() << "获取详情" << endl; 86 | closesocket(ClientSocket); 87 | WSACleanup(); 88 | return -1; 89 | } 90 | 91 | cout << "[System] 连接成功!,服务器端地址信息为:" << endl; 92 | cout << "[System] IP :" << inet_ntoa(ServerAddr.sin_addr) << " " << "端口号 :" << htons(ServerAddr.sin_port) << endl; 93 | cout << "[System] 您已成功进入聊天室,请输入您的用户名: "; 94 | 95 | // 发送名字 96 | bool st = true; 97 | string na; 98 | do { 99 | if (st) 100 | { 101 | cin >> na; 102 | st = false; 103 | } 104 | else 105 | { 106 | cout << "您输入的用户名不合规,请重新输入:"; 107 | cin >> na; 108 | } 109 | } while (na.length() > 16); 110 | strcpy_s(userName, na.c_str()); 111 | 112 | cout << "[System] 提示:如果您想退出,请输入 exit " << endl; 113 | send(ClientSocket, userName, sizeof(userName), 0); 114 | 115 | 116 | cout << endl; 117 | cout << "=========================================================" << endl; 118 | cout << endl; 119 | 120 | // 开启接收线程 121 | HANDLE recvthread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)handlerRequest, &ClientSocket, 0, 0); 122 | 123 | // 删除句柄,线程仍在运行 124 | CloseHandle(recvthread); 125 | char bufferSend[128] = { 0 }; 126 | bool start = false; 127 | while (true) 128 | { 129 | if (start) 130 | { 131 | // time函数获取从1970年1月1日0时0分0秒到此时的秒数 132 | time(&t); 133 | //将时间格式化 134 | strftime(str, 20, "%Y-%m-%d %X", localtime(&t)); 135 | //cout << str << endl; 136 | cout << '(' << str << ") "; 137 | cout << '[' << userName << "] : "; 138 | } 139 | start = true; 140 | // 用户输入发送消息 141 | cin.getline(bufferSend, 128); 142 | //如果用户输入exit准备退出 143 | if (strcmp(bufferSend, "exit") == 0) 144 | { 145 | cout << "您已离开聊天室" << endl; 146 | CloseHandle(handlerRequest); 147 | if (send(ClientSocket, bufferSend, sizeof(bufferSend), 0) == SOCKET_ERROR) 148 | return -1; //退出当前线程 149 | break; 150 | } 151 | send(ClientSocket, bufferSend, sizeof(bufferSend), 0); 152 | } 153 | closesocket(ClientSocket); 154 | WSACleanup(); 155 | system("pause"); 156 | return 0; 157 | } -------------------------------------------------------------------------------- /聊天室/多人群聊/Mul-Server.cpp: -------------------------------------------------------------------------------- 1 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 2 | #define _CRT_SECURE_NO_WARNINGS 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #pragma comment(lib,"ws2_32.lib") 12 | using namespace std; 13 | 14 | int i = 0; //标记 15 | SOCKET ServerSocket = INVALID_SOCKET; //服务端套接字 16 | SOCKADDR_IN ClientAddr = { 0 }; //客户端地址 17 | int ClientAddrLen = sizeof(ClientAddr); //客户端地址长度 18 | 19 | 20 | //在服务器端,每⼀个端⼝的服务都由⼀个单独的线程进⾏管理,同时这些线程共享⼀个⽤户列表 21 | HANDLE HandleRecv[10] = { NULL }; //接收消息线程句柄 22 | HANDLE Handle; //用于accept的线程句柄 23 | 24 | //日历时间是通过time_t数据类型来表示的,用time_t表示的时间(日历时间)是从一个时间点(例如:1970年1月1日0时0分0秒)到此时的秒数。time_t是一个长整型数: 25 | time_t t; 26 | char str[26]; 27 | 28 | //客户端信息结构体 29 | struct Client 30 | { 31 | SOCKET sClient; //客户端套接字 32 | char buffer[128]; //数据缓冲区 33 | char userName[10]; //客户端用户名,最大长度为9 34 | char identify[16]; //用于标识转发的范围 35 | char IP[20]; //客户端IP 36 | UINT_PTR flag; //标记客户端,用来区分不同的客户端 37 | } inClient[10]; //创建一个客户端结构体,最多同时10人在线 38 | 39 | 40 | //接收与发送数据线程 41 | DWORD WINAPI Rec_Send_thread(void* param) 42 | { 43 | bool Start = true; 44 | SOCKET client = INVALID_SOCKET; 45 | int flag = 0; 46 | for (int j = 0; j < i; j++) { 47 | if (*(int*)param == inClient[j].flag) //判断是为哪个客户端开辟的接收数据线程 48 | { 49 | client = inClient[j].sClient; 50 | flag = j; 51 | } 52 | } 53 | char temp[128] = { 0 }; //临时数据缓冲区 54 | string sendname, content; 55 | while (true) 56 | { 57 | //拆包,解析发送消息范围 58 | memset(temp, 0, sizeof(temp)); 59 | if (recv(client, temp, sizeof(temp), 0) == SOCKET_ERROR) 60 | continue; 61 | string contents = temp; 62 | sendname = contents.substr(0, contents.find(':')); 63 | content = contents.substr(contents.find(':') + 1 == 0 ? contents.length() : contents.find(':') + 1); 64 | if (content.length() == 0) 65 | { 66 | strcpy(inClient[flag].identify, "all"); 67 | strcpy_s(temp, sendname.c_str()); 68 | } 69 | else 70 | { 71 | strcpy(temp, content.c_str()); 72 | strcpy(inClient[flag].identify, sendname.c_str()); 73 | } 74 | memcpy(inClient[flag].buffer, temp, sizeof(inClient[flag].buffer)); 75 | 76 | if (strcmp(temp, "exit") == 0) //判断如果客户发送exit请求,那么直接关闭线程,不打开转发线程 77 | { 78 | closesocket(inClient[flag].sClient);//关闭该套接字 79 | CloseHandle(HandleRecv[flag]); //这里关闭了线程句柄 80 | inClient[flag].sClient = 0; //把这个位置空出来,留给以后进入的线程使用 81 | HandleRecv[flag] = NULL; 82 | cout << "[System] 用户 [" << inClient[flag].userName << "] " << "离开聊天室 " << endl; 83 | } 84 | else if (Start == true) 85 | { 86 | Start = false; 87 | continue; 88 | } 89 | else 90 | { 91 | time(&t); 92 | strftime(str, 20, "%Y-%m-%d %X", localtime(&t)); 93 | //cout << str << endl; 94 | cout << '(' << str << ") [" << inClient[flag].userName << "] : " << temp << endl; 95 | char temp[128] = { 0 }; //创建一个临时的数据缓冲区,用来存放接收到的数据 96 | memcpy(temp, inClient[flag].buffer, sizeof(temp)); 97 | sprintf(inClient[flag].buffer, "%s: %s", inClient[flag].userName, temp); //把发送源的名字添进转发的信息里 98 | if (strlen(temp) != 0) //如果数据不为空且还没转发则转发 99 | { 100 | // 向所有用户发送 101 | if (strcmp(inClient[flag].identify, "all") == 0) 102 | { 103 | for (int j = 0; j < i; j++) 104 | if (j != flag) 105 | //向除自己之外的所有客户端发送信息 106 | if (send(inClient[j].sClient, inClient[flag].buffer, sizeof(inClient[j].buffer), 0) == SOCKET_ERROR) 107 | return -1; 108 | } 109 | else 110 | // 向指定用户发送 111 | for (int j = 0; j < i; j++) 112 | if (strcmp(inClient[j].userName, inClient[flag].identify) == 0) 113 | if (send(inClient[j].sClient, inClient[flag].buffer, sizeof(inClient[j].buffer), 0) == SOCKET_ERROR) 114 | return 1; 115 | } 116 | } 117 | } 118 | return 0; 119 | } 120 | 121 | //接收数据线程 122 | DWORD WINAPI Accept_thread(void* param) 123 | { 124 | int flag[10] = { 0 }; 125 | while (true) 126 | { 127 | if (inClient[i].flag != 0) //找到从前往后第一个没被连接的inClient 128 | { 129 | i++; 130 | continue; 131 | } 132 | // accept()阻塞进程直到有客户端连接,接受一个特定socket请求等待队列中的连接请求 133 | //Conn_new_Socket的信息不用bind,因为它会随着serveraccept的地址传过来 134 | // accept参数:socket描述符,保存地址,保存地址长度,返回新连接的socket描述符 135 | if ((inClient[i].sClient = accept(ServerSocket, (SOCKADDR*)&ClientAddr, &ClientAddrLen)) == INVALID_SOCKET) 136 | { 137 | cout << "[System] Accept错误,请通过 " << WSAGetLastError() << "获取详情" << endl; 138 | closesocket(ServerSocket); 139 | WSACleanup(); 140 | return -1; 141 | } 142 | //接收用户名 143 | recv(inClient[i].sClient, inClient[i].userName, sizeof(inClient[i].userName), 0); 144 | cout << "[System] 客户端 [" << inClient[i].userName << "]" << " 连接成功" << endl; 145 | memcpy(inClient[i].IP, inet_ntoa(ClientAddr.sin_addr), sizeof(inClient[i].IP)); //记录客户端IP 146 | inClient[i].flag = inClient[i].sClient; //不同的socke有不同UINT_PTR类型的数字来标识 147 | i++; 148 | 149 | //遍历其他客户端并创建进程 150 | for (int j = 0; j < i; j++) 151 | { 152 | if (inClient[j].flag != flag[j]) 153 | { 154 | if (HandleRecv[j]) 155 | CloseHandle(HandleRecv[j]); 156 | //开启接收消息的线程 157 | HandleRecv[j] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Rec_Send_thread, &inClient[j].flag, 0, 0); 158 | } 159 | } 160 | for (int j = 0; j < i; j++) 161 | flag[j] = inClient[j].flag;//防止ThreadRecv线程多次开启 162 | Sleep(3000); 163 | } 164 | return 0; 165 | } 166 | 167 | int main() 168 | { 169 | WSADATA wsaData = { 0 }; 170 | 171 | //初始化套接字 172 | if (WSAStartup(MAKEWORD(2, 2), &wsaData)) 173 | { 174 | cout << "[System] WSAStartup发生错误,请通过" << WSAGetLastError() << "" << endl; 175 | return -1; 176 | } 177 | 178 | //创建套接字,IP地址类型为AF_INET(IPV-4 32位),服务类型为流式(SOCK_STREAM),Protocol(协议)为0代表系统自动选则 179 | ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 180 | if (ServerSocket == INVALID_SOCKET) 181 | { 182 | cout << "[System] Socket创建错误,请通过" << WSAGetLastError() << "获取详情" << endl; 183 | return -1; 184 | } 185 | 186 | SOCKADDR_IN ServerAddr = { 0 }; //服务端地址 187 | USHORT uPort = 10000; //服务器监听端口 188 | //设置服务器地址 189 | ServerAddr.sin_family = AF_INET;//连接方式 190 | ServerAddr.sin_port = htons(uPort);//服务器监听端口 191 | ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//宏INADDR_ANY转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的所有IP 192 | 193 | //绑定服务器 194 | if (SOCKET_ERROR == bind(ServerSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))) 195 | { 196 | cout << "[System] Bind绑定出现错误,请通过" << WSAGetLastError() << "获取详情" << endl; 197 | closesocket(ServerSocket); 198 | return -1; 199 | } 200 | 201 | // 绑定完成后开始listen,这里设置的允许等待连接的最大队列为5 202 | // 使socket进入监听状态,监听远程连接是否到来 203 | if (SOCKET_ERROR == listen(ServerSocket, 5)) 204 | { 205 | cout << "Listen监听出现错误,请通过" << WSAGetLastError() << "获取详情" << endl; 206 | closesocket(ServerSocket); 207 | WSACleanup(); 208 | return -1; 209 | } 210 | 211 | cout << "[System] 正在等待客户端连接..." << endl; 212 | 213 | Handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Accept_thread, NULL, 0, 0); 214 | cout << "[System] 提示:如果您想退出服务器,请输入 exit " << endl; 215 | cout << endl; 216 | cout << "=========================================================" << endl; 217 | cout << endl; 218 | 219 | char Serversignal[10]; 220 | cin.getline(Serversignal, 10); 221 | if (strcmp(Serversignal, "exit") == 0) 222 | { 223 | cout << "[System] 服务器已关闭" << endl; 224 | for (int j = 0; j <= i; j++) //依次关闭套接字 225 | if (inClient[j].sClient != INVALID_SOCKET) 226 | closesocket(inClient[j].sClient); 227 | CloseHandle(Handle); 228 | exit(1); 229 | closesocket(ServerSocket); 230 | WSACleanup(); 231 | } 232 | } --------------------------------------------------------------------------------