Multi-Thread TCP Server Client

prerequisite knowledge:
Basic TCP Server & Client: URL

Server

#include <stdio.h>
#include <string.h>
#include <unistd.h> // read and write (TCP); sendto and recvfrom (UDP)
#include <arpa/inet.h> // 包含#include <sys/socket.h>
#include <pthread.h>// 想要将两份参数通过一个位置传递给working 得定义一个信息结构体
struct SockInfo {struct sockaddr_in addr;int fd;
};// 由于有多个客户端 所以有多份信息 搞个数组存一下
struct SockInfo infos[512]; // 意味着我们最多只能和512个客户端*同时*通信
// 注意线程池是多个工作线程组成的队列,与此处不同/* infos需要上锁吗?不需要,每个子线程都使用了数组的一个位置,即多个线程没有操控同一内存空间*/void* working(void* arg) {struct SockInfo* pinfo = (struct SockInfo*)arg;printf("client socket %d, Address: %s:%d\n", pinfo->fd, inet_ntoa(pinfo->addr.sin_addr), ntohs(pinfo->addr.sin_port));// 5. 通信while (1) {char buf[1024];int len = recv(pinfo->fd, buf, sizeof(buf), 0);if (len > 0) {printf("client say: %s\n", buf);send(pinfo->fd, buf, len, 0); // 长度指定为len 不要传多了} else if (len == 0) {printf("客户端已经断开连接...\n");break;} else if (len == -1) {perror("recv");break;}} // 跳出后说明通信结束pinfo->fd = -1; // 回收close(pinfo->fd);return NULL;
}int main(int argc, char* argv[]) {// 1. 创建监听fdint fd = socket(PF_INET, SOCK_STREAM, 0);if (fd == -1) {perror("socket");return -1;}// 2. 绑定监听fdstruct sockaddr_in saddr;memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET;saddr.sin_port = htons(9999);saddr.sin_addr.s_addr = INADDR_ANY; // 宏INADDR_ANY(可以绑定本地)实际值是0=0.0.0.0;由于大小端没区别,因此无需htonlint ret = bind(fd, (struct sockaddr*)&saddr, sizeof(saddr));if (ret == -1) {perror("bind");return -1;}// 3. 设置监听ret = listen(fd, SOMAXCONN); // #define SOMAXCONN 128 // 最大监听队列长度 内部定义过来if (ret == -1) {perror("listen");return -1;}// 初始化信息数组int max = sizeof(infos) / sizeof(infos[0]);for (int i=0; i<max; ++i) {memset(&infos[i], 0, sizeof(infos[i]));infos[i].fd = -1; // -1表示该数组元素未被占用}// 4. 阻塞并等待客户端连接// struct sockaddr_in caddr; // 这个就不需要了// memset(&caddr, 0, sizeof(caddr));socklen_t caddr_len = sizeof(struct sockaddr_in);// 主线程不断接收:while (1) {// 创建子线程pthread_t tid;struct SockInfo* pinfo;for (int i=0; i<max; ++i) {if (infos[i].fd == -1) {pinfo = &infos[i];break;}}int cfd = accept(fd, (struct sockaddr*)&pinfo->addr, &caddr_len); // 直接传入信息数组中空闲元素的addrpinfo->fd = cfd; // 传递cfdif (cfd == -1) {perror("accept");break;}pthread_create(&tid, NULL, working, pinfo);// 此处不能使用主线程回收子线程资源 因为pthread_join是阻塞函数 与我们设想的不断accept矛盾pthread_detach(tid);}close(fd);return 0;
}

Client

#include <stdio.h>
#include <string.h>
#include <unistd.h> // read and write (TCP); sendto and recvfrom (UDP)
#include <arpa/inet.h> // 包含#include <sys/socket.h>int main(int argc, char* argv[]) {// 1. 创建通信fdint fd = socket(PF_INET, SOCK_STREAM, 0); // AF_*和PF_*值完全相同,通常混用if (fd == -1) {perror("socket");return -1;}// 2. 连接服务器struct sockaddr_in saddr;memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET;saddr.sin_port = htons(9999);inet_pton(AF_INET, "127.0.0.1", &saddr.sin_addr.s_addr);saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 或者直接指定ip: 172.31.78.11int ret = connect(fd, (struct sockaddr*)&saddr, sizeof(saddr));if (ret == -1) {perror("connect");return -1;}printf("socket connect successful!\n");// 3. 通信int number = 0;while (1) {char buf[1024];sprintf(buf, "hello, message number #%d...\n", number++); // sprintf将数据写入字符串 而非输出到标准输出流send(fd, buf, strlen(buf)+1, 0); // 注意这里不要发送sizeof(buf),发送实际字符数+'\0'memset(buf, 0, sizeof(buf)); // 有必要清空buf的int len = recv(fd, buf, sizeof(buf), 0);if (len > 0) {printf("server say: %s\n", buf);} else if (len == 0) {printf("服务器已经断开连接...\n");break;} else if (len == -1) {perror("recv");break;}sleep(1); // 让客户端1秒发一条} // 跳出后说明通信结束close(fd);return 0;
}

makefile

server:gcc -o server server.c -lpthread &gcc -o client client.cclean:rm -f server client

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/5427.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu如何更换 PyTorch 版本

环境&#xff1a; Ubuntu22.04 WLS2 问题描述&#xff1a; Ubuntu如何更换 PyTorch 版本考虑安装一个为 CUDA 11.5 编译的 PyTorch 版本。如何安装旧版本 解决方案&#xff1a; 决定不升级CUDA版本&#xff0c;而是使用一个与CUDA 11.5兼容的PyTorch版本&#xff0c;您可…

Mac远程桌面windows11

文章目录 一、Mac安装Microsoft Remote Desktop二、Window11打开远程登录权限三、常见问题 一、Mac安装Microsoft Remote Desktop 下载地址&#xff1a;点击这里官方下载 基本不用看&#xff0c;凭感觉用就行。搞不定详情见&#xff1a;官方说明 二、Window11打开远程登录权…

2024年4月个人工作生活总结

本文为 2024年4月工作生活总结。 研发编码 excel创建直方图 因工作需要&#xff0c;在excel学习使用了直方图。下面是文字版。 加载工具库&#xff1a; 直方图可在“数据”->"数据分析"中找到&#xff0c;如无&#xff0c;则要加载之。文件->选项->加载…

c#数据库: 10.调用存储过程查询信息,并显示在窗体上

查询女生信息&#xff0c;并将信息显示在窗体上: 原数据表//右键数据库名,新建查询 ------------- 新建查询窗口,添加新建存储过程Procedure_GetGirls1和查询代码如下 : CREATE PROCEDURE dbo.Procedure_GetGirls1 /*存储过程名称*/ AS SELECT * f…

[React] 手动实现CountTo 数字滚动效果

这个CountTo组件npmjs里当然有大把的依赖存在&#xff0c;不过今天我们不需要借助任何三方依赖&#xff0c;造个轮子来手动实现这个组件。 通过研究其他count to插件我们可以发现&#xff0c;数字滚动效果主要依赖于requestAnimationFrame 通过js帧来让数字动起来&#xff0c;…

【docker】Spring Boot3.x 打包 Docker容器

Docker化Spring Boot应用 创建文件夹 demo mkdir democd demo创建Dockerfile # 两个 openjdk 二选一 #FROM openjdk:17-jre-alpineFROM eclipse-temurin:17MAINTAINER chengxuyuanshitang <chengxuyuanshitangXX.com>RUN mkdir -p /workspace/java/demoCOPY demo.ja…

Python 与 TensorFlow2 生成式 AI(五)

原文&#xff1a;zh.annas-archive.org/md5/d06d282ea0d9c23c57f0ce31225acf76 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十二章&#xff1a;用生成式人工智能玩视频游戏&#xff1a;GAIL 在之前的章节中&#xff0c;我们已经看到如何使用生成式人工智能来生成…

LVGL自定义滑动

触摸和编码器都可以操作 typedef struct {lv_obj_t* obj;int16_t x;int16_t y;int16_t width;int16_t height; }pos_and_size_t;typedef struct {lv_obj_t* obj;lv_coord_t height;lv_coord_t width;lv_coord_t width_pad;lv_coord_t height_pad;lv_coord_t child_widget;lv_co…

Mybatis.net + Mysql

项目文件结构 NuGet下载Mybatis.net相关包&#xff1a;IBatisNet 安装完成后&#xff0c;会显示在&#xff0c;在已安装页面。同时&#xff0c;在管理器中的引用列表中&#xff0c;会多出来两个引用文件 IBatisNet.CommonIBatisNet.DataMapper 安装 Mysql.data。 注意&#xff…

【设计模式】14、strategy 策略模式

文章目录 十四、strategy 策略模式14.1 map_app14.1.1 map_app_test.go14.1.2 map_app.go14.1.3 navigate_strategy.go 十四、strategy 策略模式 https://refactoringguru.cn/design-patterns/strategy 需求: client 知道很多不同的策略, 希望在运行时切换. 场景示例: 就像高…

使用一等对象函数重构策略模式

目录 经典的策略模式 使用函数重构策略模式 选择最佳策略的简单模式

C++ 中 scanf 的高阶用法:scanf(“%[a-z]“,ch);

● C 中 scanf 的高阶用法&#xff1a;scanf("%[a-z]",ch);语句 scanf("%[a-z]",ch); 表示只读入小写字母入字符串。任何包含非小写字母的字符串&#xff0c;将不能读入&#xff0c;自然也不可能有输出。例如&#xff1a; 运行下面代码&#xff1a;输入 ab…

Harbor服务器停电重启后用户不能登陆怎么办?

Harbor服务问题处理 今天遇到一个问题&#xff0c;可能因为这几天下暴雨打雷比较厉害&#xff0c;办公室机房跳闸&#xff0c;有一台测试服务器没有停电保护停机。重启这台服务器以后&#xff0c;上面运行的Harbor服务登陆不上&#xff0c;用户名和密码都没改过&#xff0c;搞…

Stm32CubeMX 为 stm32mp135d 添加网卡 eth

Stm32CubeMX 为 stm32mp135d 添加网卡 eth 一、启用设备1. eth 设备添加2. eth 引脚配置2. eth 时钟配置 二、 生成代码1. optee 配置2. uboot 配置3. linux 配置 bringup 可参考&#xff1a;Stm32CubeMX 生成设备树 一、启用设备 1. eth 设备添加 我这里只启用一个eth设备&…

特斯拉与百度合作;字节正全力追赶AI业务;小红书内测自研大模型

特斯拉中国版 FSD 或与百度合作 根据彭博社的报道&#xff0c;特斯拉将通过于百度公司达成地图和导航协议&#xff0c;扫清在中国推出 FSD 功能的关键障碍。 此前&#xff0c;中国汽车工业协会、国家计算机网络应急技术处理协调中心发布《关于汽车数据处理 4 项安全要求检测情…

【漏洞复现】zookeeper AdminServer 未授权访问漏洞

0x01 产品简介 ZooKeeper 是一个集中式服务&#xff0c;用于维护配置信息、命名、提供分布式同步和提供组服务。ZooKeeper的AdminServer是其管理界面的一部分&#xff0c;通常用于监控ZooKeeper集群的状态和执行一些管理操作。AdminServer提供了Web-based的管理和监控功能&…

大数据中的项目数据采集

Datax介绍 官网&#xff1a; DataX/introduction.md at master alibaba/DataX GitHub DataX 是阿里云 DataWorks数据集成 的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。 DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS…

C#条件运算符

条件运算符分为&#xff1a;&#xff08;比较运算符 判断运算符&#xff09; 条件运算符的作用: 用于比较两个变量或者常量 判断符号: > < ! > < 条件运算符不能直接使用 需要搭配运算符使用 <u>*如果条件满足则返回true 条件不满足则返回fals…

GO解析 - Linux 指令之 lsblk

版本 lsblk --version lsblk from util-linux 2.38.1 代码 lsblkParser.go package utilstype LSBlkItem struct {Name string // 名称Major uint // 主版本Minor uint // 此版本Removable bool // 可移除deWritable bool // 可写的Size …