Linux 网络编程2 TCP并发服务器

2023-05-16

Linux 网络编程学习 TCP/IP网络编程2

    • TCP多线程服务器
    • TCP多进程服务器

在前面TCP网络编程代码的基础上进行改造,实现并发服务器功能。

TCP多线程服务器

实现功能:

  • server端可以绑定在任意IP端
  • server端停止使用crtl+p
  • client端运行./client时需加上(ip_addr, netport)
  • 支持多client链接
  • server端可打印client的ip地址和端口号

server端代码

#include "net.h"
#include <pthread.h>

typedef struct client_info{
    int newfp;
    char ipv4_addr[14];
    int port;
}Client_info, *pClient_info ;

void * process(pClient_info arg);
int main()
{
    int fp;
    struct sockaddr_in myaddr;
    // 1. open socket
    if((fp = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket fail");
        exit(0);
    }

    // 2. set bind()
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(Netport);
    // inet_aton(Netip,(int_addr *)&myaddr.sin_addr.s_addr);
    //myaddr.sin_addr.s_addr = inet_addr(Netip);
    //优化,使服务器能够接受绑定在任意IP上 INADDR_ANY
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(fp,(struct sockaddr*) &myaddr,sizeof(myaddr)) < 0)
    {
        perror("bind fail");
        exit(0);
    }

    // 3. set listen()
    if(listen(fp, BACKLOG) < 0)
    {
        perror("listen fail");
        exit(0);
    }  
 
    // 4. set accept()
    int newfp = -1;
    struct sockaddr_in recv_addr;
    socklen_t recv_addr_len = sizeof(recv_addr);
    while(1)
    {
        newfp = accept(fp, (struct sockaddr *)&recv_addr, (socklen_t *)&recv_addr_len);
        if(newfp < 0)
        {
            perror("accept fail");
            exit(0);
        }
        Client_info cin;
        bzero(cin.ipv4_addr, 16);
        if(NULL == inet_ntop(AF_INET,(void *)&recv_addr.sin_addr, cin.ipv4_addr, sizeof(recv_addr)))
        {
            perror("inet_ntop");
            exit(0);
        }
        cin.port = ntohs(recv_addr.sin_port);
        cin.newfp = newfp;
        printf("success the connet !\n");
        printf("connect ip address = %s, connect port = %d \n",cin.ipv4_addr, cin.port);

        pthread_t  tid;
        if(pthread_create(&tid, NULL, (void *)(process), &cin) != 0)
        {
            perror("thread fail");
            exit(0);
        }


    }  
    // 5. set close
    close(newfp);
    close(fp);

    return 0;

}

void * process(pClient_info cin)
{
    pthread_detach(pthread_self());  //线程分离
    int newfp = cin->newfp;
    char ipv4_addr[16] = {0};
    strcpy(ipv4_addr, cin->ipv4_addr);
    int port = cin->port;

    char buf[BUFSIZ];
    bzero(buf,BUFSIZ);
    int ret = -1;
    while(1)
    {
        do{
            ret = read(newfp, buf, BUFSIZ-1);
        }while(ret<0 && errno == EINTR);   //没有接受到数据,继续读取
        if(ret < 0)
        {
            perror("read fail");
            exit(1);
        }
        if(ret == 0)        //读取结束
        {
            break;
        }
        if(!strncmp(buf,QUIT_STR,strlen(QUIT_STR)))
        {
            printf("Client is exiting !\n");
            break;
        }
        if(!strncmp(buf,"\n",1))
        {
            bzero(buf,BUFSIZ);
        }
        printf("(%s : %d): %s \n", ipv4_addr, port,buf);
    }
    close(newfp);
    pthread_exit(NULL);     //线程结束
    pthread_join(pthread_self(),NULL);

    return NULL;
}

client端代码

#include "net.h"

int main(int argc, char* argcv[])
{
    if(argc != 3)
    {
        printf("enter error!\n");
        printf("please fill:ip_addr, netport \n");
        exit(0);
    }
    // 1. set 
    int fp = -1;
    if((fp = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket fail");
        exit(0);
    }

    // 2.set connect
    struct sockaddr_in myaddr;
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    int netport = atoi(argcv[2]);
    if(netport < 50000)
    {
        netport = Netport;
    }
    myaddr.sin_port = htons(netport);
    //myaddr.sin_addr.s_addr = inet_addr(Netip);
    if(inet_pton(AF_INET, argcv[1], (void *)&myaddr.sin_addr.s_addr) != 1)
    {
        perror("inet_pton fail");
        exit(0);
    }

    if(connect(fp,(struct sockaddr *)&myaddr, sizeof(myaddr)) < 0)
    {
        perror("connect fail");
        exit(0);
    }
    // 3. set read
    char buf[BUFSIZ];
    while(1)
    {
        bzero(buf,BUFSIZ);
        if(fgets(buf, BUFSIZ, stdin) == NULL)
        {
            continue;
        }
        write(fp, buf, strlen(buf));
        if(!strncmp(buf,QUIT_STR, strlen(QUIT_STR)))
        {
            printf("Client is exiting !\n");
            break;
        }
    }

    close(fp);

    return 0;
}

net.h头文件

#ifndef  __NET_H__
#define  __NET_H__

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>  
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define Netport 50001
#define Netip "XXX.XXX.XXX.XXX"  //ipv4地址
#define BACKLOG 5
#define QUIT_STR "quit"


#endif

TCP多进程服务器

server端
采用SIGCHLD信号来回收子进程。

#include "net.h"
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>

typedef struct client_info{
    int newfp;
    char ipv4_addr[14];
    int port;
}Client_info, *pClient_info ;

void * process(pClient_info arg);
void cil_data_handle(int signum);

int main()
{
    signal(SIGCHLD, cil_data_handle);
    int fp;
    struct sockaddr_in myaddr;
    // 1. open socket
    if((fp = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket fail");
        exit(0);
    }

    // 2. set bind()
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(Netport);
    // inet_aton(Netip,(int_addr *)&myaddr.sin_addr.s_addr);
    //myaddr.sin_addr.s_addr = inet_addr(Netip);
    //优化,使服务器能够接受绑定在任意IP上 INADDR_ANY
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(fp,(struct sockaddr*) &myaddr,sizeof(myaddr)) < 0)
    {
        perror("bind fail");
        exit(0);
    }

    // 3. set listen()
    if(listen(fp, BACKLOG) < 0)
    {
        perror("listen fail");
        exit(0);
    }  
 
    // 4. set accept()
    int newfp = -1;
    struct sockaddr_in recv_addr;
    socklen_t recv_addr_len = sizeof(recv_addr);
    while(1)
    {
        newfp = accept(fp, (struct sockaddr *)&recv_addr, (socklen_t *)&recv_addr_len);
        if(newfp < 0)
        {
            perror("accept fail");
            exit(0);
        }
        Client_info cin;
        bzero(cin.ipv4_addr, 16);
        if(NULL == inet_ntop(AF_INET,(void *)&recv_addr.sin_addr, cin.ipv4_addr, sizeof(recv_addr)))
        {
            perror("inet_ntop");
            exit(0);
        }
        cin.port = ntohs(recv_addr.sin_port);
        cin.newfp = newfp;
        printf("success the connet !\n");
        printf("connect ip address = %s, connect port = %d \n",cin.ipv4_addr, cin.port);

        // pthread_t  tid;
        // if(pthread_create(&tid, NULL, (void *)(process), &cin) != 0)
        // {
        //     perror("thread fail");
        //     exit(0);
        // }
        pid_t pid;
        if((pid = fork()) < 0 )
        {
            perror("fork fail");
            exit(0);
        }
        else if(pid == 0)       //子进程
        {
            close(fp);
            process(&cin);
            return 0;
        }
        else                    // 父进程
        {
            close(newfp);
        }


    }  
    // 5. set close
    close(fp);

    return 0;

}

void * process(pClient_info cin)
{
    pthread_detach(pthread_self());  //线程分离
    int newfp = cin->newfp;
    char ipv4_addr[16] = {0};
    strcpy(ipv4_addr, cin->ipv4_addr);
    int port = cin->port;

    char buf[BUFSIZ];
    bzero(buf,BUFSIZ);
    int ret = -1;
    while(1)
    {
        do{
            ret = read(newfp, buf, BUFSIZ-1);
        }while(ret<0 && errno == EINTR);   //没有接受到数据,继续读取
        if(ret < 0)
        {
            perror("read fail");
            exit(1);
        }
        if(ret == 0)        //读取结束
        {
            break;
        }
        if(!strncmp(buf,QUIT_STR,strlen(QUIT_STR)))
        {
            printf("Client is exiting !\n");
            break;
        }
        if(!strncmp(buf,"\n",1))
        {
            bzero(buf,BUFSIZ);
        }
        printf("(%s : %d): %s \n", ipv4_addr, port,buf);
    }
    close(newfp);
    
    return NULL;
}

void cil_data_handle(int signum)
{
    if(signum == SIGCHLD)
    {
        waitpid(-1, NULL, WNOHANG);
    }
}


client端

#include "net.h"

int main(int argc, char* argcv[])
{
    if(argc != 3)
    {
        printf("enter error!\n");
        printf("please fill:ip_addr, netport \n");
        exit(0);
    }
    // 1. set 
    int fp = -1;
    if((fp = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket fail");
        exit(0);
    }

    // 2.set connect
    struct sockaddr_in myaddr;
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    int netport = atoi(argcv[2]);
    if(netport < 50000)
    {
        netport = Netport;
    }
    myaddr.sin_port = htons(netport);
    //myaddr.sin_addr.s_addr = inet_addr(Netip);
    if(inet_pton(AF_INET, argcv[1], (void *)&myaddr.sin_addr.s_addr) != 1)
    {
        perror("inet_pton fail");
        exit(0);
    }

    if(connect(fp,(struct sockaddr *)&myaddr, sizeof(myaddr)) < 0)
    {
        perror("connect fail");
        exit(0);
    }
    // 3. set read
    char buf[BUFSIZ];
    while(1)
    {
        bzero(buf,BUFSIZ);
        if(fgets(buf, BUFSIZ, stdin) == NULL)
        {
            continue;
        }
        write(fp, buf, strlen(buf));
        if(!strncmp(buf,QUIT_STR, strlen(QUIT_STR)))
        {
            printf("Client is exiting !\n");
            break;
        }
    }

    close(fp);

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

Linux 网络编程2 TCP并发服务器 的相关文章

  • 基于51单片机的简单方波发生器

    一个按键可以调整频率的简易方波信号发生器 xff0c 当频率超出范围时LED亮 xff0c 频率范围是100 1000hz include lt reg52 h gt sbit PWMOUT 61 P1 0 sbit LED1 61 P2
  • matlab绘制垂线(x轴或y轴)

    使用line函数就可以绘制垂线 1 绘制垂直于x轴的垂线 line xvalue xvalue y1 y2 xff1b 比如绘制x 61 5 y取值为 0 10 xff1b line 5 5 0 10 2 绘制垂直于y轴的垂线 line x
  • ubuntu解决中文乱码

    1 查看当前系统使用的字符编码 locale LANG 61 en US LANGUAGE 61 en US LC CTYPE 61 34 en US 34 LC NUMERIC 61 34 en US 34 LC TIME 61 34 e
  • ROS 在工作空间中创建python程序

    ROS 在工作空间中创建python程序 基于ros xff0c 在工作空间catkin ws中创建pkg和python程序 xff0c 并进行编译使其可以用rosrun进行运行 xff0c 参考 xff1a 参考 默认前面已经创建了cat
  • 关于AD15铺铜的注意事项

    1 在铺好信号线和电源线后再考虑是否在铺地之前先手动连接地线 因为在铺地时有一个间距问题 xff0c 如果有限地线的间距太小 xff0c 那么在铺地时就会不成功 xff0c 导致墨迹个地没有被接进去 还有就是要考虑敷铜时的间距 xff0c
  • AD15 建立铺铜间距规则

    系统默认的普通间距就是系统的clearance 10mil xff0c 可是默认普通出来的话间距太小了 xff0c 于是乎可以建立一个普通规则 xff0c 但是要注意你所建立的铺铜规则优先级永远在默认优先级之前 xff08 比如你的poly
  • AD15 修改铺铜(去除自己不想要的铺铜区域)

    1 点击place gt polygon pour cutout 2 出现光标 xff0c 然后把你想要去除的那个区域选中 xff0c 如图一所示 xff0c 单击右键退出选择模式 3 双击没有被选中的区域 xff0c 软件提示重新铺铜 x
  • 串口缓冲区管理分析

    一 概述 xff1a 串口使用时一般包含两个缓冲区 xff0c 即发送缓冲区和接收缓冲区 发送数据时 xff0c 先将数据存在发送缓冲区 xff0c 然后通过串口发送 xff1b 接收数据时 xff0c 先将接收的数据存在接收缓冲区 xff
  • JLINK给STM32下载的两种模式--jtag & sw连线及配置

    jtag线就不说了 xff0c 将jlink的Vref GND TMS TCK分别接至SW接口 对于STM32F103RCT6来说 xff1a TMS PA12 xff0c TCK PA14 关于KEIL MDK中的设置如下图所示就可以了
  • 3.3V过压保护电路

    好久没写了 xff0c 今天就写一些工作中用到的一个电路 3 3V过压保护电路 通常一个电路中给单片机等对电压信息敏感的器件供电时都会小心翼翼 xff0c 严防前级降压电路出问题 xff0c 我就碰到过12V转5V的1117奔溃记过加在ST
  • eagle使用注意点

    使用eagle也有快一年时间了 xff0c 刚开始很不习惯 xff0c 后来习惯了也还可以 xff0c 这里我举出几个设计中经常出错的地方 xff1a 1 PCB翻转问题 xff1a 在翻转PCB文件时一定要打开torigin borigi
  • 自制pixhawk电脑不识别com口

    在原版pix上面进行改版很方便 xff0c 可以去除很多不必要的电路 笔者将电源管理芯片去除 xff0c 5V来源于变压器输出或者是连接电脑时的USB供电 xff0c 并将它们并联起来 xff0c 但是板子做回来焊接后发现问题如下 xff1
  • eagle pcb v8.2 便捷性大大提升

    eagle pcb在被Autodesk收购之前是7 x版本 xff0c 但是却有一些一直被吐槽的东西 xff0c 说实话这些东西确实增加了布线难度 xff0c 增加了布板时间 xff1a 1 real time DRC xff1a 在7 x
  • Ubuntu firefox 显示在运行无法打开,如何在终端关闭进程

    用top命令找不到firfox的进程 xff0c 查看某个用户运行的进程 xff1a ps u username grep eclipse 查看用户名为 xff1a username 的用户是否运行了eclipse 查看用户当前运行fire
  • 【万字详解】cJSON解析

    目录 1 通过README文件 xff0c 初步了解cJSON xff1a 1 1 头文件的开头和结尾 xff1a 1 2 头文件关于cJSON类型的宏定义 1 3 头文件中的extern 2 阅读并且分析cJSON源码 2 1 结构体st
  • VINS-mono 解析 新特征

    在17 12 29 xff0c VINS更新了代码加入了新的特征 xff0c 包括map merge 地图合并 pose graph reuse 位姿图重利用 online temporal calibration function 在线时
  • VINS-mono 位姿图 重利用测试

    在前一篇博文里介绍了VINS mono pose graph reuse功能的使用 xff0c 这里接着贴出一些延伸的测试 xff0c 并进行一些探讨 延伸测试 一般来说 xff0c 加载地图是进行非GPS定位必要的一步 这里根据新的VIN
  • 2022年全国大学生电子设计大赛省赛A题

    2022年全国大学生电子设计大赛省赛A题 交流电子负载 文章目录 2022年全国大学生电子设计大赛省赛A题 交流电子负载 前言一 总体思路二 模块设计1 半桥模块2 测量模块3 辅助电源模块 三 主电路搭建总结 前言 2022年全国大学生电
  • linux下使用shell发送http请求

    一 curl 1 get请求 curl命令默认下就是使用get方式发送http请求 curl www baidu com 2 post请求 使用 d参数 xff0c 形式如下 xff1a curl d 34 param1 61 value1
  • 网络摄像头 接口协议 ONVIF,PSIA,CGI,ISAPI

    ONVIF致力于通过全球性的开放接口标准来推进网络视频在安防市场的应用 xff0c 这一接口标准将确保不同厂商生产的网络视频产品具有互通性 2008年11月 xff0c 论坛正式发布了ONVIF第一版规范 ONVIF核心规范1 0 随着视频

随机推荐

  • VLC架构及流程分析

    注明 xff1a 此文为转载 原文地址 xff1a https jiya io archives vlc learn 2 html 由于本人之前由于在工作中需要对VLC进行二次开发 因此进行了相关工作的开发 xff08 由于工作原因 目前暂
  • 学习、使用C++开发是不是过时了?

    C 43 43 在开发过程中真心很尴尬 1 拿相同薪水使用不同语言的程序员 xff0c 开发大多数相同的常见业务需求 xff0c C 43 43 总是进度较慢 xff08 不考虑时 空复杂性及效率 xff09 2 扩展性 跨平台 资源 内存
  • strcat()函数的用法

    这几天的一次程序练习中用到了strcat 函数 xff0c 但也想到了一些问题 我们都知道strcat str ptr 是将字符串ptr内容连接到字符串str后 xff0c 然后得到一个组合后的字符串str xff0c 比如 str字符串内
  • libQtCore.so.4 undefined symbol :g_main_context_push_thread_default

    开发板终端执行qt程序 qtDemo qws 报错 xff1a libQtCore so 4 undefined symbol g main context push thread default 解决方案 xff1a cd DVSDK p
  • curl时设置Expect的必要性

    curl 在项目中使用频率较高 xff0c 比如内部接口 第三方 api 图片存储服务等 xff0c 但是我们在使用 curl 时可能并没有注意到 Expect 这个请求头信息 xff0c 而 Expect 设置不正确 xff0c 会导致不
  • 奇偶校验原理

    奇校验 xff1a 求一个字节8位中 1 的个数 xff0c 添加一位校验位 xff0c 使9位中 1 的个数为奇数 xff1b 偶校验同理 奇校验就是让原有数据序列中 xff08 和要加上的一位 xff09 1的个数为奇数 如010001
  • CreateMutex函数函数用来实现进程互斥

    CreateMutex函数 正常情况下 xff0c 一个进程的运行一般是不会影响到其他正在运行的进程的 但是对于某些有特殊要求的如以独占方式使用串行口等硬件设备的程序就要求在其进程运行期间不允许其他试图使用此端口设备的程序运行的 xff0c
  • C++与QML交互总结

    一直对于QT的理解和使用都停留在主窗口程序和控制台程序 xff0c 虽然QT的新东西QML听过也接触过 xff0c 但是基本上没梳理过调用流程 趁着旧项目要使用QML技术 xff0c 现在就将C 43 43 和QML交互进行总结 目录 一
  • QT下TCP协议实现数据网络传输

    QT开发框架以其跨平台的优势 xff0c 在全世界IT界如雷贯耳 其封装了功能齐全的各种类 xff0c 大大的提高了开发者的效率 本篇内容将介绍如何使用QT 6 4 1框架开发服务器和客户端程序 xff0c 让两端能够首发消息 xff0c
  • 从零实现vins-mono+fast-planner+M100无人机实验在现实场景中的应用

    版权声明 本文为博主原创文章 未经博主允许不能随意转载 本文链接 https blog csdn net AnChenliang 1002 article details 109535355 最近由于科研的需要 要将VINS mono与fa
  • Linux下C语言实现HTTP文件服务器和TCP协议实现网络数据传输

    在实际开发中经常用到web框架 xff0c 比如Servlet xff0c SpringBoot等 xff0c 这些开发框架提高了我们的开发效率 xff0c 节省了开发时间 但是这会令我们技术人员处于浮云之上 xff0c 看不到其本质 说实
  • Linux下C语言UDP协议通信实践

    UDP和TCP协议一样 xff0c 都是传输层协议 是无连接的 xff0c 不安全的 xff0c 报式传输层协议 xff0c 通信过程默认也是阻塞的 其通信特点主要如下 xff1a xff08 1 xff09 不需要建立连接 xff0c 所
  • Ubuntu下PyQt5使用总结

    因为工作中需要给交付团队开发桌面工具 xff0c 考虑到交付团队多使用Mac xff0c 调研了一下发现PyQt5可以实现跨平台 xff0c 满足工具开发需要 xff0c 就用其开发了桌面工具 现以ubuntu开发环境为例总结一下开发过程
  • ubuntu下安装配置grpc

    目录 1 准备环境 2 安装protobuf 3 安装cares库 3 安装grpc 1 17 x 1 准备环境 sudo apt get install pkg config sudo apt get install autoconf a
  • cmake管理子程序,lib库和so库应用实践

    cmake在管理大型项目时经常被用到 xff0c 本文以简单程序演示来说明camke管理项目应用 xff0c 其中包括主程序 xff0c 子程序 xff0c so库程序 xff0c lib程序 目录 1 程序目录结构 2 编译执行 3 清除
  • GIt常用命令总结

    目录 1 创建新建分支 2 强制拉去代码 3 合并相邻提交 xff0c 保证只有一个commit信息 4 本地回退 5 查看git修改列表 6 提交代码 7 切换新分支并从服务端拉取最新 8 git cherry pick合并代码使用 9
  • Linux 下I/O多路复用总结

    xfeff xfeff select xff0c poll xff0c epoll都是IO多路复用的机制 I O多路复用就通过一种机制 xff0c 可以监视多个描述符 xff0c 一旦某个描述符就绪 xff08 一般是读就绪或者写就绪 xf
  • WAV文件头分析

    WAV语音文件头部含有44字节的标志信息 xff0c 其含义如下 xff1a ckid xff1a 4字节 RIFF 标志 xff0c 大写 wavHeader 0 61 39 R 39 wavHeader 1 61 39 I 39 wav
  • Linux环境下限制网速和取消限制网速

    查看网卡信息 ip addr root 64 rabbitmq01 ip addr 1 lo lt LOOPBACK UP LOWER UP gt mtu 65536 qdisc noqueue state UNKNOWN qlen 1 l
  • Linux 网络编程2 TCP并发服务器

    Linux 网络编程学习 TCP IP网络编程2 TCP多线程服务器TCP多进程服务器 在前面TCP网络编程代码的基础上进行改造 xff0c 实现并发服务器功能 TCP多线程服务器 实现功能 xff1a server端可以绑定在任意IP端s