当前位置: 首页 > news >正文

C++多线程服务器

C++多线程服务器

因为自己同时在看多本书,之前看过《TCP/IP 网络编程》一书,其中有一个自己编写一个多线程服务器的例子,于是就把代码直接抄了一变。

在学习网络编程前需要先了解网络的7层模型。

具体代码如下:

服务器端:

include <iostream>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <process.h>
#pragma comment(lib,"Ws2_32.lib")
using namespace std;#define BUF_SIZE 100
#define MAX_CLNT 256unsigned WINAPI HandleClient(void* pvoid);
void SendMeg(const char* pMsg,int nLen);
void ErrorHandle(const char* pMsg);int nCountClient = 0;
SOCKET clntSocket[MAX_CLNT];
HANDLE hMutex;int main(int argc,char* argv[])
{WSADATA wsaData;SOCKET hServSock, hClntSock;SOCKADDR_IN servAdr, clntAdr;int clntAdrSz;HANDLE hTread;if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0){ErrorHandle("WSAStartup Error");}hMutex = CreateMutex(NULL,FALSE,NULL);hServSock = socket(PF_INET,SOCK_STREAM,0);memset(&servAdr,0,sizeof(servAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);servAdr.sin_port = htons(9000);if (bind(hServSock, (SOCKADDR*)&servAdr,sizeof(servAdr)) == SOCKET_ERROR){ErrorHandle("bind Error");}if (listen(hServSock,5) == SOCKET_ERROR){ErrorHandle("listen Error");}while (1){clntAdrSz = sizeof(clntAdr);cout << "[Server]:Wait for client to Connect..." << endl;hClntSock = accept(hServSock,(sockaddr*)&clntAdr,&clntAdrSz);::WaitForSingleObject(hMutex,INFINITE);clntSocket[nCountClient++] = hClntSock;ReleaseMutex(hMutex);hTread = (HANDLE)_beginthreadex(NULL,0, HandleClient,(void*)&hClntSock,0,NULL);printf("[Server]:Connenct Client IP:%s\n",inet_ntoa(clntAdr.sin_addr));}closesocket(hServSock);WSACleanup();return 0;
}unsigned WINAPI HandleClient(void* pvoid)
{SOCKET hClntSock = *((SOCKET*)(pvoid));int strLen = 0;int i;char szBuff[BUF_SIZE];memset(szBuff,0, sizeof(char)*BUF_SIZE);while ((strLen = recv(hClntSock, szBuff, sizeof(szBuff), 0)) != 0){printf("[Server]:recv %s from Client.\n",szBuff);SendMeg(szBuff, strLen);}::WaitForSingleObject(hMutex, INFINITE);for (i = 0;i< nCountClient;i++){// 移除断开连接的套接字if (hClntSock == clntSocket[i]){while (i++ < nCountClient - 1){clntSocket[i] = clntSocket[i + 1];}break;  }}nCountClient--;ReleaseMutex(hMutex);closesocket(hClntSock);return 0;
}void SendMeg(const char* pMsg, int nLen)
{int i;::WaitForSingleObject(hMutex, INFINITE);for (int i=0;i< nCountClient;i++){send(clntSocket[i], pMsg, nLen,0);printf("[Server]:send %s to Client.\n",pMsg);}ReleaseMutex(hMutex);
}void ErrorHandle(const char* pMsg)
{fputs(pMsg,stderr);fputc('\n',stderr);exit(1);
}

代码说明:其中修改了一下在控制台中输出的信息。

客户端代码:

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <process.h>
#pragma comment(lib,"Ws2_32.lib")
using namespace std;#define BUF_SIZE 100
#define NAME_SIZE 20unsigned WINAPI SendMsg(void* arg);
unsigned WINAPI RecvMsg(void* arg);
void ErrorHandle(const char* msg);char name[NAME_SIZE] = "[DEFAULT]";
char msg[BUF_SIZE];int main(int argc,char* argv[])
{WSADATA wsaData;SOCKET hSock;SOCKADDR_IN servAdr;HANDLE hSndThread, hRcvThread;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ErrorHandle("WSAStartup Error()");}hSock = socket(PF_INET,SOCK_STREAM,0);memset(&servAdr,0,sizeof(servAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");servAdr.sin_port = htons(9000);if (connect(hSock,(sockaddr*)&servAdr,sizeof(servAdr)) == SOCKET_ERROR){ErrorHandle("Connect Error");}cout << "Connect To Server success" << endl;hSndThread = (HANDLE)_beginthreadex(NULL,0,SendMsg,(void*)(&hSock),0,NULL);hRcvThread = (HANDLE)_beginthreadex(NULL,0,RecvMsg, (void*)(&hSock), 0, NULL);WaitForSingleObject(hSndThread,INFINITE);WaitForSingleObject(hRcvThread,INFINITE);closesocket(hSock);WSACleanup();return 0;
}unsigned WINAPI SendMsg(void* arg)
{SOCKET hSock = *((SOCKET*)arg);char nameMsg[BUF_SIZE + NAME_SIZE];while (1){cout << "[Client]:Please enter your msg to send to Server..." << endl;fgets(msg, BUF_SIZE,stdin);if (strcmp(msg,"q\n") == 0||strcmp(msg,"Q\n") == 0){closesocket(hSock);exit(0);}send(hSock,msg,strlen(msg),0);printf("[Client]:send %s to Server\n", msg);}return 0;
}unsigned WINAPI RecvMsg(void* arg)
{SOCKET hSock = *((SOCKET*)arg);char nameMsg[BUF_SIZE + NAME_SIZE];int strLen;while (1){strLen = recv(hSock, nameMsg, BUF_SIZE + NAME_SIZE-1,0);if (strLen == -1)return-1;nameMsg[strLen] = 0;printf("[Client]:recv %s From Server\n", nameMsg);}return 0;
}void ErrorHandle(const char* msg)
{fputs(msg, stderr);fputc('\n', stderr);exit(1);
}

流程说明:先运行服务器,等待客户端的连接,客户端连接后由客户端输入字符串,然后发送给服务器,服务器再把接受到的字符串发回给客户端,这样就是一个回声服务器了。

代码运行效果:

wechat_2025-08-10_160759_866
有关多线程网络编程的更多内容,大家可以参考《TCP/IP 网络编程》一书。

http://www.lryc.cn/news/616386.html

相关文章:

  • Spring循环依赖详解
  • MySQL面试题及详细答案 155道(041-060)
  • LeeCode 46. 全排列
  • 冒泡排序实现以及优化
  • 20250810 | 深度学习入门笔记1
  • 大型动作模型LAM:让企业重复任务实现80%效率提升的AI技术架构与实现方案
  • 五种 IO 模型与阻塞 IO
  • 数组中的第K个最大元素
  • MyBatisPlus插件原理
  • Leetcode 3646. Next Special Palindrome Number
  • 代码随想录算法训练营第六十天|图论part10
  • 【Nginx②】 | Nginx部署前端静态文件指南(基于虚拟机环境)
  • 浏览器CEFSharp88+X86+win7 之多页面展示(四)
  • NodeJs学习日志(4):路由合并_环境配置_常用文件目录
  • element-ui el-progress在有小数的情况下,会换行显示。解决不换行的问题。
  • iceberg安装部署
  • Rust面试题及详细答案120道(11-18)-- 控制流与函数
  • vulnhub-Drippingblues靶机
  • 通过Certbot自动申请更新HTTPS网站的SSL证书
  • 瑞芯微 RK3588 平台驱动开发 学习计划
  • CST支持对哪些模型进行特征模仿真?分别有哪些用于特征模分析的求解器?
  • C语言——深入理解指针(二)
  • 【东枫科技】FR3 可扩展测试平台,适用于 6G 研究与卫星通信,高达 1.6 GHz 的带宽
  • 【秋招笔试】2025.08.09美团秋招算法岗机考真题-第三题
  • Python 的浅拷贝 vs 深拷贝(含嵌套可变对象示例与踩坑场景)
  • OpenGL VAO 概念、API 和示例
  • 每日一题:使用栈实现逆波兰表达式求值
  • TypeScript中的type和interface的区别是什么?
  • 从街亭失守看管理
  • WAV音频数据集MFCC特征提取处理办法