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.pswp.cn/bicheng/92828.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/92828.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/92828.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Pandas】常用數據處理技巧

一. 數據讀取 1.pd.to_csv & pd.read_csv 細節&#xff1a; 1.pd.read_csv 需要 ignore_index True or ,index_col0 否則會有列Unnamed0 2.pickle具有更快的讀取速度&#xff0c;與更小的體積。 讀取前N行&#xff08;若不需獲取所有數據&#xff09; pd.read_csv(…

Docker Compose 部署高可用 MongoDB 副本集集群(含 Keepalived + HAProxy 負載均衡)

Docker Compose 部署高可用 MongoDB 副本集集群&#xff08;含 Keepalived HAProxy 負載均衡&#xff09;背景與目標&#x1f4cb; 環境規劃**服務器信息****軟件版本**部署步驟1. 創建目錄結構2、生成 keyFile&#xff08;三臺機器內容必須一致&#xff09;3. 準備 Keepalive…

MySQL(189)如何分析MySQL的鎖等待問題?

分析MySQL的鎖等待問題有助于發現和解決數據庫性能瓶頸。鎖等待問題通常會導致數據庫響應時間變長&#xff0c;影響系統的整體性能。以下是詳細深入的方法和代碼示例&#xff0c;幫助你分析和解決MySQL的鎖等待問題。 一、鎖的類型和概念 在MySQL中&#xff0c;主要有以下幾種鎖…

26.Scikit-learn實戰:機器學習的工具箱

Scikit-learn實戰&#xff1a;機器學習的工具箱 &#x1f3af; 前言&#xff1a;機器學習界的"宜家家具" 還記得第一次逛宜家的感受嗎&#xff1f;琳瑯滿目的家具&#xff0c;每一件都有詳細的說明書&#xff0c;組裝簡單&#xff0c;樣式統一&#xff0c;關鍵是—…

wordpress文章摘要調用的3種方法

以下是WordPress文章摘要的3種調用方法&#xff1a; 1. 使用the_excerpt()函數 這是WordPress自帶的函數&#xff0c;用于調用文章摘要。如果文章有手動填寫的摘要&#xff0c;則會顯示手動摘要;如果沒有手動摘要&#xff0c;WordPress會自動從文章內容中提取前55個單詞作為摘…

java excel轉圖片常用的幾種方法

十分想念順店雜可。。。在 Java 中實現 Excel 轉圖片&#xff0c;常用的方法主要分為兩類&#xff1a;使用商業庫&#xff08;簡單高效但可能收費&#xff09;和使用開源庫組合&#xff08;免費但實現復雜&#xff09;。以下是幾種常用方案及實現思路&#xff1a;一、使用商業庫…

QT項目 -仿QQ音樂的音樂播放器(第五節)

目錄 一、CommonPage界?設置和顯示 二、自定義ListItemBox 三、支持hover效果 四、自定義VolumeTool 五、界面設置 六、頁面創建及彈出 七、繪制三角 一、CommonPage界面設置和顯示 void CommonPage::setCommonPageUI(const QString &title, const QString &imag…

wstool和git submodule優劣勢對比

wstool 和 git submodule 都可以用來管理項目中的外部源代碼依賴&#xff0c;但它們的設計理念、工作流程和適用場景有很大不同。 我們來深入對比一下它們的優勢和劣勢。 核心理念比喻 git submodule&#xff1a;像是在你的汽車設計圖紙中&#xff0c;直接嵌入了另一家公司&…

六、RuoYi-Cloud-Plus OSS文件上傳配置

1.前面我們完成了RuoYi-Cloud-Plus 部署及啟動&#xff0c;此刻已經可以正常訪問。 前面文章的專欄內容在這&#xff0c;感興趣可以看看。 https://blog.csdn.net/weixin_42868605/category_13023920.html 2.但現在雖然已經啟動成功&#xff0c;但有很多功能我們依舊用不了&a…

達夢數據庫日常運維命令

查詢數據庫表空間數據文件使用大小限制DECLARE K INT:(SELECT cast(PAGE()/1024 as varchar)); BEGIN SELECTF."PATH" 數據文件 ,F.CLIENT_PATH,G.NAME 所屬表空間,F.MAX_SIZE||M 文件擴展限制,(CASE F.AUTO_EXTEND WHEN 1 THEN 是 ELSE 否 END) 文件…

使用線性降維方法進行數據降維

在數據科學與機器學習的領域中&#xff0c;維度災難問題經常導致模型的性能下降。線性降維方法是一種常見的技術&#xff0c;用于在保留盡可能多的原始數據特征的同時&#xff0c;減少數據集的維度。這些方法通過將高維數據映射到低維空間來減少特征數量&#xff0c;從而加速模…

OpenCV圖像裁剪與 ROI 操作

在圖像處理領域&#xff0c;ROI&#xff08;Region of Interest&#xff09;區域感興趣操作是非常基礎而重要的一環。無論是進行目標檢測、圖像分割&#xff0c;還是簡單的圖像處理&#xff0c;都離不開對圖像某一區域的選取與處理。本文將結合 OpenCV 的 C 接口&#xff0c;詳…

關于AI應用案例計算機視覺、自然語言處理、推薦系統和生成式AI四大領域的詳細技術分析。

一、計算機視覺應用&#xff1a;實時物體檢測 案例描述&#xff1a;使用YOLOv8模型實現實時物體檢測系統&#xff0c;應用于安防監控場景。 1. 代碼示例&#xff08;Python&#xff09; python from ultralytics import YOLO import cv2# 加載預訓練模型 model YOLO("…

各個網絡層擁有的協議簡寫

OSI 七層模型&#xff08;從下到上分別為物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層&#xff09;是網絡通信的經典理論框架&#xff0c;每層都有其核心功能和對應的協議。以下是各層的主要協議列舉&#xff1a;1. 物理層&#xff08;Physical Layer&#xff…

django基于Python的設計師作品平臺的數據可視化系統設計與實現

django基于Python的設計師作品平臺的數據可視化系統設計與實現

等保測評-RabbitMQ中間件

RabbitMQ-docker部署查看版本&#xff1a;rabbitmqctl version、rabbitmqctl status | grep version配置文件&#xff1a;一般為rabbitmq.conf端口號&#xff1a;一般為15672一、身份鑒別a&#xff09;應對登錄的用戶進行身份標識和鑒別&#xff0c;身份標識具有唯一性&#xf…

Linux操作系統從入門到實戰(十六)馮諾依曼體系結構,操作系統與系統調用和庫函數概念

Linux操作系統從入門到實戰&#xff08;十六&#xff09;馮諾依曼體系結構&#xff0c;操作系統與系統調用和庫函數概念前言一、馮諾依曼體系結構1. 馮諾依曼體系是什么&#xff1f;2. 核心部件有哪些&#xff1f;3. 數據是怎么跑的&#xff1f;4. 發文件的流程也一樣5. 為什么…

廣東省省考備考(第七十二天8.10)——言語理解與表達、判斷推理(強化訓練)

小模考&#xff08;言語、常識&#xff09; 錯題解析 本題可從第二空入手。轉折前后語意相反&#xff0c;轉折前指出“投資對經濟拉動只能發揮短期的作用”&#xff0c;故轉折后應表達“最終消費對經濟拉動才能發揮長期的作用”。A項“持久”、D項“長期”均符合文意&#xff0…

數據庫刪除術:邏輯刪除 vs 物理刪除,選錯毀所有

你以為刪除數據就是點個按鈕&#xff1f;背后藏著數據安全的生死抉擇&#xff01; 本文揭秘兩種刪除方式的本質區別&#xff0c;用真實案例教你避免災難性數據丟失。一、刪除的本質:數據消失的兩種方式 &#x1f9ea; #mermaid-svg-pVylRd9e5p4VE5G0 {font-family:"trebuc…

【Python 小腳本·大用途 · 第 3 篇】

1. 痛點 100 字 硬盤里散落著 IMG_2024(1).jpg、IMG_2024(1) (1).jpg、下載目錄里同名但大小不同的視頻…… 手動比對既耗時又容易誤刪。今天用 30 行 Python 腳本&#xff0c;基于「內容哈希」一鍵找出并刪除重復文件&#xff0c;支持多目錄遞歸、白名單、空目錄清理。2. 腳本…