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

【嵌入式开发之网络编程】TCP并发实现

在实例中,经常会存在多个客户端向服务端发送连接请求和传递数据的情况,为了解决这个问题,我们需要利用多进程或者多线程来实现并发。

TCP多进程并发

要想实现TCP多进程并发,就要从accept函数下手,每次接收到来自客户端的请求,都生成一个新的文件描述符,记录下客户端的地址信息(IP和端口号),然后通过新文件描述符用read函数读取传送的内容。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); - 功能:接收客户端连接,默认是一个阻塞的函数,阻塞等待客户端连接 - 参数: - sockfd : 用于监听的文件描述符 - addr : 传出参数,记录了连接成功后客户端的地址信息(ip,port)- addrlen : 指定第二个参数的对应的内存大小 - 返回值: - 成功 :用于通信的文件描述符 - -1 : 失败 

服务端实现代码

客户端代码与【嵌入式开发之网络编程】Socket套接字及TCP通信的实现中一致,关于进程创建和回收,参考【嵌入式开发之并发程序设计】进程的创建和回收

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <signal.h>
#include <sys/wait.h>#define BACKLOG 5
void SigHandle(int sig) {if (sig == SIGCHLD) {printf("client exited\n");wait(NULL);}
}
void ClientHandle(int newfd);int main(int argc, const char *argv[])
{int fd, newfd;struct sockaddr_in addr, clint_addr;socklen_t addrlen = sizeof(clint_addr);#if 1struct sigaction act;act.sa_handler = SigHandle;act.sa_flags = SA_RESTART;sigemptyset(&act.sa_mask);sigaction(SIGCHLD, &act, NULL);
#elsesignal(SIGCHLD, SigHandle);
#endifpid_t pid;if (argc < 3) {fprintf(stderr, "%s<addr><port>\n", argv[0]);exit(0);}/*创建套接字* 使用IPv4互联网协议* 流式套间字* 协议唯一对应*/if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket");exit(0);}addr.sin_family = AF_INET;addr.sin_port = htons(atoi(argv[2]));
#if 0addr.sin_addr.s_addr = inet_addr(argv[1]);
#elseif (inet_aton(argv[1], &addr.sin_addr) == 0) {fprintf(stderr, "Invalid address\n");exit(EXIT_FAILURE);}
#endif//地址快速重用int flag = 1, len = sizeof(int);if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -1) {perror("setsockopt");exit(1);}//绑定通信结构体if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {perror("bind");exit(0);}//设置套接字为监听模式if (listen(fd, BACKLOG) == -1) {perror("listen");exit(0);}while(1) {//接受客户端的连接请求,生成新的和客户端通信的套间字if ((newfd = accept(fd, (struct sockaddr *)&clint_addr, &addrlen)) < 0) {perror("accept");exit(0);}/*IP地址转换成点分十进制* 端口号网络字节序转成主机字节序* 生成子进程,并读取数据*/printf("addr:%s port:%d\n", inet_ntoa(clint_addr.sin_addr), ntohs(clint_addr.sin_port));if ((pid = fork()) < 0) {perror("fork");exit(0);} else if (pid == 0) {close(fd);ClientHandle(newfd);exit(0);} else {close(newfd);}}close(fd);return 0;
}void ClientHandle(int newfd) {int ret;char buf[BUFSIZ] = {};while(1){memset(buf, 0, BUFSIZ);ret = read(newfd, buf, BUFSIZ);if (ret < 0){perror("read");exit(0);} else if (ret == 0) {break;} else {printf("buf = %s\n", buf);}}close(newfd);
}

运行结果(服务端)

$ ./server 0 8888
addr:127.0.0.1 port:54564
buf = woeoeoeaddr:127.0.0.1 port:47698
buf = woeooe

TCP多线程并发

服务端实现代码

这部分涉及到线程的创建,参考【嵌入式开发之并发程序设计】线程的基本概念、pthread线程库的创建、互斥锁的使用、条件变量以及线程池的概念和使用

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <pthread.h>#define BACKLOG 5void *ClinetHandle(void *arg);
int main(int argc, char *argv[])
{int fd, newfd;struct sockaddr_in addr, clint_addr;pthread_t tid;socklen_t addrlen = sizeof(clint_addr);if(argc < 3){fprintf(stderr, "%s<addr><port>\n", argv[0]);exit(0);}/*创建套接字*/fd = socket(AF_INET, SOCK_STREAM, 0);if(fd < 0){perror("socket");exit(0);}addr.sin_family = AF_INET;addr.sin_port = htons( atoi(argv[2]) );if ( inet_aton(argv[1], &addr.sin_addr) == 0) {fprintf(stderr, "Invalid address\n");exit(EXIT_FAILURE);}/*地址快速重用*/int flag=1,len= sizeof (int); if ( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -1) { perror("setsockopt"); exit(1); } /*绑定通信结构体*/if(bind(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){perror("bind");exit(0);}/*设置套接字为监听模式*/if(listen(fd, BACKLOG) == -1){perror("listen");exit(0);}while(1){/*接受客户端的连接请求,生成新的用于和客户端通信的套接字*/newfd = accept(fd, (struct sockaddr *)&clint_addr, &addrlen);if(newfd < 0){perror("accept");exit(0);}printf("addr:%s port:%d\n", inet_ntoa(clint_addr.sin_addr), ntohs(clint_addr.sin_port) );/*创建线程,并设置分离属性*/pthread_create(&tid, NULL, ClinetHandle, &newfd);pthread_detach(tid);}close(fd);return 0;
}
void *ClinetHandle(void *arg){int ret;char buf[BUFSIZ] = {};int newfd = *(int *)arg;while(1){//memset(buf, 0, BUFSIZ);bzero(buf, BUFSIZ);ret = read(newfd, buf, BUFSIZ);if(ret < 0){perror("read");exit(0);}else if(ret == 0)break;elseprintf("buf = %s\n", buf);}printf("client exited\n");close(newfd);return NULL;
}

运行结果(服务端)

$ ./server 0 8888
addr:127.0.0.1 port:59782
buf = Hello worldaddr:127.0.0.1 port:34552
buf = haodeclient exited
client exited

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 主场竞争,安踏把背影留给耐克
  • Java13 网络编程
  • 【pytorch】固定(freeze)住部分网络
  • MyBatis一级缓存和二级缓存以及 mybatis架构
  • 五指生望京新店开业,开启健康之旅
  • 用AppleScript做macOS UI自动化
  • 外卖系统开发:如何打造一个无缝衔接的用户体验?
  • 建模模型时间说明
  • GPT应用篇:如何用GPT4.0写一本言情小说?
  • atsec出席2024 PCI社区会议
  • 什么软件可以约束员工摸鱼行为?黑神话悟空爆火!上班玩游戏,职场新利器来啦
  • 目标 CDC实例数据库更改密码,预定启动报错SQL 错误代码为“-30082”。SQL 状态为:08001。
  • Haporxy搭建web集群
  • docker 数据存储
  • 财经群里看猴?!苏轼:转念的力量——早读(逆天打工人爬取热门微信文章解读)
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • java8 Stream Pipelines 浅析
  • mysql常用命令汇总
  • October CMS - 快速入门 9 Images And Galleries
  • react 代码优化(一) ——事件处理
  • React中的“虫洞”——Context
  • Redis的resp协议
  • Selenium实战教程系列(二)---元素定位
  • 测试如何在敏捷团队中工作?
  • 理解 C# 泛型接口中的协变与逆变(抗变)
  • 排序(1):冒泡排序
  • 日剧·日综资源集合(建议收藏)
  • 容器服务kubernetes弹性伸缩高级用法
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • ​水经微图Web1.5.0版即将上线
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #HarmonyOS:Web组件的使用
  • #WEB前端(HTML属性)
  • (24)(24.1) FPV和仿真的机载OSD(三)
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (层次遍历)104. 二叉树的最大深度
  • (差分)胡桃爱原石
  • (代码示例)使用setTimeout来延迟加载JS脚本文件
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (没学懂,待填坑)【动态规划】数位动态规划
  • (五)网络优化与超参数选择--九五小庞
  • (小白学Java)Java简介和基本配置
  • (一)kafka实战——kafka源码编译启动
  • (一)utf8mb4_general_ci 和 utf8mb4_unicode_ci 适用排序和比较规则场景
  • (原創) 如何將struct塞進vector? (C/C++) (STL)
  • (转)Linq学习笔记
  • (转)linux下的时间函数使用
  • (转)Linux整合apache和tomcat构建Web服务器
  • (转)Scala的“=”符号简介
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • ****Linux下Mysql的安装和配置
  • *算法训练(leetcode)第四十五天 | 101. 孤岛的总面积、102. 沉没孤岛、103. 水流问题、104. 建造最大岛屿
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案