高并發服務器-使用多線程(Multi-Thread)實現【C語言】

在上期的socket套接字的使用詳解中(socket套接字的使用詳解)最后實現的TCP服務器只能處理一個客戶端的請求發送,當有其他客戶端請求連接時會被阻塞。為了能同時處理多個客戶端的連接請求,本期使用多線程的方式來解決。

程序流程

  1. 創建監聽套接字:使用 socket 函數創建套接字 lfd
  2. 綁定套接字:使用 bind 函數將套接字綁定到指定的 IP 地址和端口。
  3. 監聽連接請求:使用 listen 函數開始監聽連接請求。
  4. 等待并接受客戶端連接:使用 accept 函數等待并接受客戶端連接請求。
  5. 獲取客戶端地址信息:使用 getpeername 函數獲取已連接客戶端的 IP 地址和端口號。
  6. 創建線程處理客戶端請求:使用 pthread_create 函數創建新線程處理該連接,并設置線程為分離屬性。
  7. 線程處理客戶端通信:在 handle_client 函數中處理與客戶端的通信,包括讀取請求、處理數據、發送響應。
  8. 主線程繼續監聽新的連接請求:主線程關閉新的客戶端套接字,由新線程處理。繼續循環等待新的客戶端連接請求。

示例代碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <ctype.h>// 處理客戶端通信的函數
void *handle_client(void *arg) {int cfd = *(int *)arg;free(arg);struct sockaddr_in client_addr;socklen_t client_addr_len = sizeof(client_addr);//getpeername 函數獲取與套接字 cfd 關聯的遠程(客戶端)地址信息,并將其存儲在 client_addr 結構體中。getpeername(cfd, (struct sockaddr *)&client_addr, &client_addr_len);    char client_ip[INET_ADDRSTRLEN];inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));int client_port = ntohs(client_addr.sin_port);printf("Client connected: IP [%s], PORT [%d], FD [%d]\n", client_ip, client_port, cfd);char buf[1024];int n;while ((n = read(cfd, buf, sizeof(buf))) > 0) {for (int i = 0; i < n; i++) {buf[i] = toupper(buf[i]);}write(cfd, buf, n);}printf("Client disconnected: IP [%s], PORT [%d], FD [%d]\n", client_ip, client_port, cfd);close(cfd);return NULL;
}int main() {// 創建監聽套接字int lfd = socket(AF_INET, SOCK_STREAM, 0);if (lfd < 0) {perror("socket error");return -1;}// 綁定套接字struct sockaddr_in serv_addr;bzero(&serv_addr, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(8888);serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("bind error");close(lfd);return -1;}// 監聽連接請求if (listen(lfd, 5) < 0) {perror("listen error");close(lfd);return -1;}while (1) {struct sockaddr_in client_addr;socklen_t client_addr_len = sizeof(client_addr);int *cfd = malloc(sizeof(int));*cfd = accept(lfd, (struct sockaddr *)&client_addr, &client_addr_len);if (*cfd < 0) {perror("accept error");free(cfd);continue;}// 創建線程處理客戶端請求pthread_t tid;pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // 設置線程分離屬性if (pthread_create(&tid, &attr, handle_client, cfd) != 0) {perror("pthread_create error");close(*cfd);free(cfd);}pthread_attr_destroy(&attr);}close(lfd);return 0;
}

客戶端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8888
#define BUFFER_SIZE 1024
#define SERVER_IP "127.0.0.1"int main() {int sock = 0, valread;struct sockaddr_in serv_addr;char buffer[BUFFER_SIZE] = {0};char input_buffer[BUFFER_SIZE] = {0};char *hello = "Hello from client";int opt = 1;// 創建 TCP 套接字if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket creation failed");return -1;}// 設置服務器地址結構serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);// 將 IPv4 地址從文本轉換為二進制形式if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {perror("Invalid address/ Address not supported");return -1;}// 連接服務器if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("Connection Failed");return -1;}printf("Connected to server\n");// 循環發送消息并接收響應while (1) {printf("Enter message to send (or 'exit' to quit): ");fgets(input_buffer, BUFFER_SIZE, stdin);// 去掉輸入的換行符input_buffer[strcspn(input_buffer, "\n")] = 0;// 如果輸入是 'exit',則退出循環if (strcmp(input_buffer, "exit") == 0) {break;}// 發送消息給服務器send(sock, input_buffer, strlen(input_buffer), 0);printf("Message sent to server: %s\n", input_buffer);// 接收服務器的響應valread = read(sock, buffer, BUFFER_SIZE);printf("Server response: %s\n", buffer);memset(buffer, 0, sizeof(buffer));}close(sock);return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/46213.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/46213.shtml
英文地址,請注明出處:http://en.pswp.cn/web/46213.shtml

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

相關文章

爬蟲案例(讀書網)(下)

上篇鏈接&#xff1a; CSDN-讀書網https://mp.csdn.net/mp_blog/creation/editor/139306808 可以看見基本的全部信息&#xff1a;如(author、bookname、link.....) 寫下代碼如下&#xff1a; import requests from bs4 import BeautifulSoup from lxml import etreeheaders{…

scottplot5 中 使用signalXY圖,如何更新數據?

&#x1f3c6;本文收錄于《CSDN問答解答》專欄&#xff0c;主要記錄項目實戰過程中的Bug之前因后果及提供真實有效的解決方案&#xff0c;希望能夠助你一臂之力&#xff0c;幫你早日登頂實現財富自由&#x1f680;&#xff1b;同時&#xff0c;歡迎大家關注&&收藏&…

總部下達任務時,如何保證員工的執行力?

執行力是個體基于戰略目標&#xff0c;有效整合利用資源&#xff0c;保質保量完成預定目標的操作能力&#xff0c;員工執行力的高低是企業完成效益、成果轉化的關鍵。執行力包含完成任務的意愿、完成能力、完成程度三個維度&#xff0c;其中意愿是基礎和出發點&#xff0c;能力…

物聯網與通信技術

查了很多資料&#xff0c;也夾雜著一些自己的見解。此篇文章僅探討三個問題&#xff1a;物聯網與通信技術的關系&#xff1b;5G為物聯網帶來了什么&#xff0c;物聯網真的需要5G嗎&#xff1b;物聯網發展的現實問題。 1、物聯網與通信技術的關系 最近幾年&#xff0c;物聯網的…

Apache POI 使用Java處理Excel數據 進階

1.POI入門教程鏈接 http://t.csdnimg.cn/Axn4Phttp://t.csdnimg.cn/Axn4P建議&#xff1a;從入門看起會更好理解POI對Excel數據的使用和處理 記得引入依賴&#xff1a; <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactI…

CentOS搭建 Mono 開發環境

Mono 是一個由 Xamarin 公司所主持的自由開放源代碼項目,該項目的目標是創建一系列匹配ECMA標準的.NET工具,包括 C# 編譯器和通用語言架構,Mono項目不僅可以運行于Windows系統上,還可以運行于Linux,FreeBSD,Unix,OS X和Solaris,甚至一些游戲平臺,本實驗帶您搭建 Mono …

Linux chmod 命令簡介

在Linux中&#xff0c;chmod 命令用于改變文件或文件夾的訪問權限。要改變一個文件夾及其內部所有文件和子文件夾的權限&#xff0c;您可以使用遞歸選項 -R。以下是一些常用的 chmod 命令示例&#xff1a; 給所有用戶讀、寫和執行權限&#xff1a; chmod -R 777 /path/to/direc…

JVM高頻面試點

文章目錄 JVM內存模型程序計數器Java虛擬機棧本地方法棧Java堆方法區運行時常量池 Java對象對象的創建如何為對象分配內存 對象的內存布局對象頭實例數據對齊填充 對象的訪問定位 垃圾收集器找到垃圾引用計數法可達性分析&#xff08;根搜索法&#xff09; 引用概念的擴充回收方…

【Socket套接字編程】(實現TCP和UDP的通信)

&#x1f387;&#x1f389;&#x1f389;&#x1f389;點進來你就是我的人了 博主主頁&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳&#xff0c;歡迎大佬指點&#xff01; 人生格言: 當你的才華撐不起你的野心的時候,你就應該靜下心來學習! 歡迎志同道合的朋友…

java序列化與反系列化,serializable原理,Parcelable接口原理解析,Json,XML

Java的序列化和反序列化是用于對象的持久化和傳輸的重要機制。以下是對相關概念的詳細解釋&#xff1a; Java 序列化與反序列化 序列化 (Serialization) 是將 Java 對象轉換為字節流的過程&#xff0c;這樣對象就可以通過網絡傳輸或者保存到文件中。反序列化 (Deserializatio…

創建通用JS公共模塊并發布至npm

title: 創建通用JS公共模塊并發布至npm tags: UMD rollup verdaccio npm categories: 模塊化 概要內容 創建&#xff1a;JS公共模塊 打包&#xff1a;使用rollup 打包公共模塊 發布&#xff1a;js公共模塊至verdaccio平臺 發布&#xff1a;js公共模塊至npm平臺 如何創建JS公共模…

【PostgreSQL】Windows 上安裝 PostgreSQL 16版本

博主介紹:?全網粉絲20W+,CSDN博客專家、Java領域優質創作者,掘金/華為云/阿里云/InfoQ等平臺優質作者、專注于Java技術領域? 技術范圍:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大數據、物聯網、機器學習等設計與開發。 感興趣的可…

二叉樹遍歷(C++)

題目描述 樹和二叉樹基本上都有先序、中序、后序、按層遍歷等遍歷順序&#xff0c; 給定中序和其它一種 遍歷的序列就可以確定一棵二叉樹的結構。 假定一棵二叉樹一個結點用一個字符描述&#xff0c;現在給出中序和按層遍歷的字符串&#xff0c;求該樹 的先序遍歷字符串。 輸…

【Python】TensorFlow介紹與實戰

TensorFlow介紹與使用 1. 前言 在人工智能領域的快速發展中&#xff0c;深度學習框架的選擇至關重要。TensorFlow 以其靈活性和強大的社區支持&#xff0c;成為了許多研究者和開發者的首選。本文將進一步擴展對 TensorFlow 的介紹&#xff0c;包括其優勢、應用場景以及在最新…

基于jeecgboot-vue3的Flowable流程仿釘釘流程設計器-支持VForm3表單的選擇與支持

因為這個項目license問題無法開源&#xff0c;更多技術支持與服務請加入我的知識星球。 1、初始化的時候加載表單 /** 查詢表單列表 */ const getFormList () > {listForm().then(res > formOptions.value res.result.records) } 2、開始節點的修改&#xff0c;增加表…

計算機的錯誤計算(三十四)

摘要 用錯數預測 &#xff08;或 pow(a,x)&#xff09;函數的結果中含有的錯誤數字的個數&#xff0c;并與Visual Studio 和Excel 的輸出中含有的錯誤位數相比較。結果顯示&#xff0c;預測與實際一致。 對于 &#xff08;或 pow(a,x)&#xff09;函數&#xff0c;根據 與 的不…

C# 靜態變量與動態變量的區別及用法

在 C# 中&#xff0c;"靜態變量"與"動態變量"并不是直接相關的概念&#xff0c;但可以根據您的問題提供一些解釋。靜態變量和動態變量通常與變量的生命周期和類型綁定相關。以下是兩者的一些區別&#xff1a; 靜態變量&#xff08;Static Variables&#…

3.RabbitMQ安裝-Centos7

官方網址&#xff1a;gInstalling RabbitMQ | RabbitMQ 安裝前提&#xff0c;需要一個erlang語言環境。 下載 erlang: Releases rabbitmq/erlang-rpm GitHub rabbitmq-server: 3.8.8 Releases rabbitmq/rabbitmq-server GitHub 安裝命令 (說明i表示安裝&#xff…

SCI一區級 | Matlab實現SSA-CNN-GRU-Multihead-Attention多變量時間序列預測

目錄 效果一覽基本介紹程序設計參考資料 效果一覽 基本介紹 1.【SCI一區級】Matlab實現SSA-CNN-GRU-Multihead-Attention麻雀算法優化卷積門控循環單元融合多頭注意力機制多變量時間序列預測&#xff0c;要求Matlab2023版以上&#xff1b; 2.輸入多個特征&#xff0c;輸出單個…

Python--MySQL及其使用

1. MySQL 簡介 MySQL 是一個開源的關系型數據庫管理系統&#xff08;RDBMS&#xff09;&#xff0c;廣泛用于各種應用程序&#xff0c;支持多種操作系統。它使用 SQL 語言進行數據查詢、管理和操作。 2. MySQL 的主要特點 跨平臺&#xff1a;支持多種操作系統&#xff0c;如…