Linux下多线程网络通讯--多线程网络通讯

2023-10-27

Linux下多线程网络通讯--多线程网络通讯/要多个线程

核心知识点:

  1. 主线程和子线程
  2. 子线程的剥离
  3. 主线程使用范围 子线程使用范围
  4. 主线程的数据传到子线中
  5. 思考范围

思考范围

  1. 多线程网络通讯–>1个服务器, 多个客户端连接服务器, 在主线程里监听并连接这些客户端, 由于客户端的ip不同,所以每一个服务器和客户端通讯的socket的文件文件描述符内容是不一样的, 所以需要一个很大的数组来保存每一个客户端的ip和端口
  2. 整体可以才拆解为两个部分:1.上面的连接 2. 下面的通信部分, 由于每个客户端的ip不一样+传送的内容不一样, 需要每个客户端都有一个专门的通信函数,也就是创建出多个线程,1个线程为1个客户端服务(通信)

源代码

服务器端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>

#define SIZE 512

// 信息结构体  包含Socket 和通信文件描述符fd
struct SockInfo
{
	struct sockaddr_in addr; // 包含ip和端口
	int fd;
};

// 创建N个客户端需要的信息结构体 512个客户端
struct SockInfo infos[SIZE];


void* working(void* arg);

int main()
{

	// 1.创建服务器监听socket
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd == -1)
	{
		perror("服务器创建Socket失败");
		return -1;
	}

	// 2.套接字和本地的ip绑定 IP地址和端口号
	struct sockaddr_in saddr;
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(9999);// 注意大小端转换
	saddr.sin_addr.s_addr = INADDR_ANY;
	int ret = bind(fd, (struct sockaddr*)&saddr, sizeof(saddr));
	if(ret == -1)
	{
		perror("绑定失败");
		return -1;
	}

	// 3.设置监听
	ret = listen(fd, 128);			// 最大监听128个
	if(ret == -1)
	{
		perror("监听失败");
		return -1;
	}
	
	// 初始化信息结构体数组(= ip端口组合体 + 文件描述符)
	int max = sizeof(infos) / sizeof(infos[0]);
	for(int i = 0; i < max; i++)
	{
		bzero(&infos[i],  sizeof(infos[i]));
		infos[i].fd = -1;
	}

	// 4.阻塞并且等待客户端链接==创建客户端socket
	int addrlen = sizeof(struct sockaddr_in);
	// 不断连接客户端
	while(1)
	{
		struct SockInfo* pinfo;
		for(int i = 0; i < max; i++)
		{
			if(infos[i].fd == -1)
			{
				pinfo = &infos[i];
				break;
			}
		}
		
		// cfd 通信文件描述符, 在子线程里使用
		int cfd = accept(fd, (struct sockaddr*)&pinfo->addr, &addrlen);
		pinfo->fd = cfd;
		if(cfd == -1)
		{
			perror("客户端连接错误");
			break; // 可以重新尝试连接  使用contiue
		}
		//创建子线程
		pthread_t tid;
		pthread_create(&tid, NULL, working, pinfo);
		// 分离子线程 
		pthread_detach(tid);
	}
	close(fd);

	return 0;
}


// 子线程任务函数
void* working(void* arg)
{
	struct SockInfo* pinfo = (struct SockInfo*)arg;
	char ip[32];
	printf("IP地址为: %s, 端口号: %d\n", inet_ntop(AF_INET, 
				&pinfo->addr.sin_addr.s_addr, ip, sizeof(ip)),
				ntohs(pinfo->addr.sin_port));

	// 5.通信
	while(1)
	{
		char Buff[1024];
		int len = recv(pinfo->fd, Buff, sizeof(Buff), 0);
		if(len > 0)
		{
			printf("client say: %s\n",Buff);
			send(pinfo->fd, Buff, len, 0);		// 发送数据 
		}else if(len == 0)
		{
			printf("客户端 断开连接\n");
			break;
		}
		else
		{
			perror("接收数据错误");
			break;
		}
	}

	// 6.关闭文件描述符 
	close(pinfo->fd);
	pinfo->fd = -1;
	return NULL;
}

客户端

客户端代码不变

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

int main()
{
	// 1.创建通信的套接字
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd == -1)
	{
		perror("创建通信socket失败");
		return -1;
	}

	// 2.连接服务器  绑定服务器的ip和端口
	struct sockaddr_in saddr;
	// 初始化绑定的接口体
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(9999); //注意大小端转换
	inet_pton(AF_INET, "192.168.1.1", &saddr.sin_addr.s_addr);	
	int ret = connect(fd, (struct sockaddr*)&saddr, sizeof(saddr));
	if(ret == -1)
	{
		perror("连接错误");
		return -1;
	}
	
	int number = 0;
	while(1)
	{	
		// 3.通信
		char Buff[1024];
		sprintf(Buff, "通信中..., %d \n", number++);
		// 发送数据,通信的套接字  数据  实际长度 0 
		send(fd, Buff, strlen(Buff)+1, 0);

		// 4. 接收数据前先清空数据
		memset(Buff, 0 , sizeof(Buff));
		// 接收数据
		int len = recv(fd, Buff, sizeof(Buff), 0);
		if(len > 0)
		{
			printf("Server say: %s\n", Buff);	
		}else if(len == 0)
		{
			printf("连接断开");
			break;
		}else
		{
			perror("Recv");
			break;
		}
		sleep(1);
	}

	// 5. 关闭文件描述符;
	close(fd);
	return 0;
}


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux下多线程网络通讯--多线程网络通讯 的相关文章

  • 如何在内核内部使用性能计数器?

    我想访问内核内部的性能计数器 我发现了很多在用户空间中使用性能计数器的方法 但是你能告诉我一些在内核空间中使用这些计数器的方法吗 Please 不指定工具名称 我想写自己的代码 最好是内核模块 我使用的是内核为 3 18 1 的 Ubunt
  • 在 Linux 上使用命令行 PHP 检查互联网连接

    我在 Linux 上使用命令行 PHP 来打开蓝牙拨号连接 并且我需要一种快速的方法来检查互联网连接是否处于活动状态 嗯 不一定要脏 但要快 使用exec运行外部命令不是问题 我正在考虑 ping 一些稳定的服务器 例如谷歌 但我想知道是否
  • Bash:使用参数扩展查找和替换

    我想更换输入法 find string include 圆进度 38px 30px 4eb630 和输出 输出字符串 include 圆进度 38px 30px using find string pattern replacement s
  • Linux内核如何阻止BIOS系统调用?

    BIOS 调用在 Linux 操作系统中不可用 我想知道内核如何阻止执行包含对 BIOS 子例程的调用的指令 The BIOS http en wikipedia org wiki Basic Input Output System主要在
  • Windows 上的 DLL Main 与 Windows 上的 DLL Main Linux 上的 __attribute__((constructor)) 入口点

    考虑代码 EXE int main printf Executable Main loading library n ifdef HAVE WINDOWS HMODULE lib LoadLibraryA testdll dll elif
  • 监控(嗅探)由 FTDI USB 串行转换器创建的 /dev/ttyUSB0

    我想监视 嗅探 由 FTDI USB 串行转换器创建的 dev ttyUSB0 的流量 我已经在 Windows 中编写了自己的应用程序 现在我尝试将其移植到 Linux 并使用 dev tty USB0 我想调试实际发生的通信 软件 st
  • platform.linux_distribution() 已弃用 - 有哪些替代方案?

    从 Python 3 5 开始platform linux distribution https docs python org 3 5 library platform html platform linux distribution已弃
  • “原子”系统调用是什么意思?

    我知道atomic通常在以下上 下文中使用竞争条件意思是类似一致性 and 根据多线程 多处理环境确定结果 没关系 但最近我读到了Linux中的原子系统调用 但不明白什么是atomic实际上这里的意思是 即how this 原子性 is 实
  • 尽管 EXPORT_SYMBOL 模块插入时出现“模块中的未知符号”

    我正在尝试编译并插入 r8169 realtek 以太网驱动程序 我的内核版本是 ebin sony uname r 4 2 0 rc3 custom 我的本地磁盘中有相同的完整源代码 用于安装当前的内核 当我运行时该模块编译成功make
  • 如何从子进程为父进程设置环境变量?

    如何从子进程为父进程设置环境变量 例如 我有父进程和子进程 子进程继承自父进程环境变量 TMP VARIABLE 777 如何将子进程中 TMP VARIABLE 的值更改为 999 使其值对父进程可见 因为 TMP VARIABLE 99
  • 在linux中将数据“广播”到多个进程的规范方法?

    我有一个应用程序需要将数据流从一个进程发送到多个读取器 每个读取器都需要查看自己的流副本 这是相当高的速率 100MB s 并不罕见 因此我希望尽可能避免重复 在我的理想世界中 Linux 应该有支持多个读取器的命名管道 并为常见的单读取器
  • 何时调用setsockopt?在bind()和connect()之前?

    我继承了一些 TCP 代码 调用 bind tcpSocket struct sockaddr server addr sizeof server addr 在致电之前 setsockopt tcpSocket SOL SOCKET SO
  • 为什么不使用 sshrc 中设置的 $PATH?

    我正在尝试在 OS X 服务器上通过 ssh 设置 svn 为了做到这一点 我读到我需要一个包装器来设置 umask 并 在我的例子中 设置存储库根 一种快速而肮脏的方法是重命名 usr bin svnserve并将包装器脚本放置在该位置
  • 如何使用c在Linux中获取当前时间戳(以纳秒为单位)

    我知道我们可以使用clock gettime CLOCK MONOTONIC 我尝试问的问题是 如果我需要以纳秒为单位的时间 从时代来看 这将是一个巨大的数字 例如 自纪元以来的秒数是13438461673 so 13438461673 1
  • 我应该如何从非 root Debian Linux 守护进程登录?

    我正在编写一个新的守护进程 它将托管在 Debian Linux 上 我发现 var log 具有仅 root 写入权限 因此我的守护进程无法在那里写入日志文件 但是 如果它写入那里 它似乎将获得自动日志轮转 并且也按照用户期望的方式工作
  • c - 后台运行的程序的退出状态

    我有一个任务 其中我必须创建一个迷你 shell 它能够执行很多操作 包括作业控制 我设法使用 fork 和 execvp 创建新的工作 但我还想获取 execvp 运行的程序的退出代码 根据我从其他帖子中查找到的内容 我可以使用以下方法来
  • SDL/C++ OpenGL 程序,如何阻止 SDL 捕获 SIGINT

    我在用SDL http www libsdl org 用于在 Linux 上运行的 OpenGL 应用程序 我的问题是 SDL 正在捕获 SIGINT 并忽略它 这是一个痛苦 因为我正在通过屏幕会话进行开发 并且我无法使用 CTRL C 终
  • 32 位 x86 汇编中堆栈对齐的职责

    我试图清楚地了解谁 调用者或被调用者 负责堆栈对齐 64 位汇编的情况相当清楚 它是由caller 请参阅系统 V AMD64 ABI 第 3 2 2 节栈帧 输入参数区域的末尾应按 16 对齐 32 如果 m256 在堆栈 字节边界上传递
  • H.323,如何制作一个没有媒体的简单环。该脚本遵循 Q.931 设置,但仍然无法正常工作

    谁能帮我解决这个问题吗 当我发送此请求时 我在wireshark中看到数据包将发送到1720 tcp端口中的SJPhone 但 SJPhone 仍然没有响铃 我想让它响起 无论媒体 我非常感谢您的支持 我一定缺少消息协议细节来实现这个 请给
  • Linux 堆栈大小

    我正在寻找 Linux 内核中堆栈的良好描述 但我发现找到任何有用的东西出奇地困难 我知道大多数系统的堆栈限制为 4k 而其他系统则限制为 8k 我假设每个内核线程 下半部分都有自己的堆栈 我还听说 如果中断发生 它会使用当前线程的堆栈 但

随机推荐

  • 智能合约-ERC20接口方法详解

    官方文档 EIP 20 Token Standard 实现Demo https github com ConsenSys Tokens blob fdf687c69d998266a95f15216b1955a4965a0a6d contra
  • Java调用C语言DLL文件方法

    有时候我们经常要在 JAVA中调用C语言DLL文件 下面我们将用一个例题来向大家介绍 JAVA调用C语言DLL文件的实现方法 一 生成C的头文件 1 编辑Main java public class Main public native s
  • 嘴说手画Spark的存储系统

    Spark本身并不存储数据 这里所说的存储系统是指计算过程中 管理内存中数据 如读到内存的源数据 缓存的RDD数据 广播数据 Shuffle文件数据的功能模块 如果没有存储管理系统 计算是无法完成的 存储系统的主要由以下组件构成 Block
  • 建立时间裕量和保持时间裕量

    前面的博客里面有讲解建立时间Tsetup和保持时间Tholdon的概念以及要满足的和时钟之间的关系 这里不再重复 在了解建立时间裕量和保持时间裕量之前我们先来了解一下触发沿Launch Edges 和锁存沿Latch Edges 一般认为L
  • Redis(四)Redis集群搭建

    Redis集群搭建 pwd命令主要用于打印当前工作目录的工作路径 Keepalived Redis服务器的高可用除了用集群和哨兵模式外 还可以用keepalived Keepalived的作用是检测服务器的状态 如果有一台web服务器宕机
  • shader学习过程3——shader编程语言

    shader language最初是由汇编语言编写 难度高 入门难 现在由三种高级语言可以编写 一 HLSL 基于DirectX的High Level Shading Language 简称HLSL DirectX简称DX 微软的产品 优点
  • stm32--USB(作为U盘)+FatFs的实现

    一 USB功能的添加 作为U盘 添加文件 将官方库中的Library文件夹中的所有有效文件添加到工程中 分为4个文件夹 usb class为硬件相关 Library Class usb driver为底层驱动 Driver usb libr
  • 如何制作多系统启动U盘

    Ventoy简介 简单来说 Ventoy是一个制作可启动U盘的开源工具 并且它有诸多优势 有了Ventoy你就无需反复地格式化U盘 你只需要把 ISO WIM IMG VHD x EFI 等类型的文件直接拷贝到U盘里面就可以启动了 无需其他
  • openssl: error while loading shared libraries: libssl.so.1.1

    在执行openssl version出现如下错误 openssl error while loading shared libraries libssl so 1 1 cannot open shared object file No su
  • HyperLPR车牌识别相关资源整理

    一 HyperLPR使用 源码分析相关资料 1 HyperLPR中文车牌识别 中给出了视频文件的处理方法 可以参考下 因为识别检测本身比较耗时 所以从画面上看 视频文件播放非常慢 这里需要根据上层应用根据自己的需要进行丢帧处理 PlateR
  • 16-Ansible常用模块-service模块

    一 概述 service 模块可以帮助我们管理远程主机上的服务 比如 启动或停止远程主机中的 nginx 服务 注意 假如想要管理远程主机中的某个服务 那么这个服务必须能被 BSD init OpenRC SysV Solaris SMF
  • 机器人教育的魅力是什么

    机器人教育指通过设计 组装 编程 运行机器人 激发学生学习兴趣 培养学生综合能力 它融合了机械原理 电子传感器 计算机软硬件及人工智能等众多先进技术 对学生能力 素质的培养有着巨大的作用 与传统的编程教育不同 机器人教育往往通过形象生动的图
  • 计算机视觉论文-2021-07-14

    本专栏是计算机视觉方向论文收集积累 时间 2021年7月14日 来源 paper digest 欢迎关注原创公众号 计算机视觉联盟 回复 西瓜书手推笔记 可获取我的机器学习纯手推笔记 直达笔记地址 机器学习手推笔记 GitHub地址 1 T
  • QT——键盘事件(捕获按键事件)

    文章目录 qt增加按键事件处理响应 qt增加按键事件处理响应 在使用qt时 当需要处理按键触发的键盘事件的时候 需要用到事件触发响应 查阅文档 QT已经实现了这一系列的键盘事件 void QWidget keyPressEvent QKey
  • 基于python的人脸识别系统设计与实现

    案例分享之基于python的人脸识别系统设计与实现 人脸识别即程序对输入的图像进行判别是否有人脸 并识别出有人脸的图像所对应的人 即我们常说的人脸识别一般包含了人脸检测和人脸识别两部分 下面对其在opencv中的相应模块进行分别介绍 在op
  • Spark kryo Jar包冲突问题排查

    错误日志 Exception in thread adaptive query stage 0 java lang NoSuchMethodError com esotericsoftware kryo Kryo setInstantiat
  • 3GPP简介及标准查找指南

    3GPP是积极倡导UMTS为主的第三代标准化组织 成立于1998年12月 是一个协作协议 3GPP最初的工作范围是第三代移动系统指定全球使用的技术规范与技术报告 第三代移动系统是基于发展的GSM核心网络和它们所支持的无线接入技术 随后3GP
  • mysql:列类型之enum、set

    环境 window10 vs2022 net 6 mysql 8 0 25 DBeaver 参考 mysql 11 3 5 The ENUM Type 注意 在mysql中定义enum和set应该使用英文字母 本文使用汉字是为了方便阅读 1
  • UE4 控件蓝图与蓝图的交互

    我现在想实现的是点击场景中的一个蓝图中的某个静态网格体 然后在控件蓝图中的文本控件中就能显示这个被点击的静态网格体的名称 效果 步骤 首先我在控件蓝图中对其中的一个文本控件创建了一个绑定函数 绑定函数的逻辑如下 整车 内部无系统 是我添加的
  • Linux下多线程网络通讯--多线程网络通讯

    Linux下多线程网络通讯 多线程网络通讯 要多个线程 核心知识点 思考范围 源代码 服务器端 客户端 核心知识点 主线程和子线程 子线程的剥离 主线程使用范围 子线程使用范围 主线程的数据传到子线中 思考范围 思考范围 多线程网络通讯 g