美文网首页
多线程自定义协议通信

多线程自定义协议通信

作者: arkliu | 来源:发表于2022-12-03 08:17 被阅读0次

接上篇标题

服务器每接收到一个客户端请求,就开启一个线程,循环读取客户端发来的数据,并向客户端发送数据,当客户端close或者关闭练连接后,打印此次关闭的客户端的ip地址和端口号。

服务器端

#include <arpa/inet.h>
#include <netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#include<signal.h>
#include<errno.h>
#include<time.h>
#include <sys/types.h>  
#include <sys/wait.h>
#include<pthread.h>
#include "msg.h"

int sockfd;

void sig_handler(int signo) {
    if (signo == SIGINT){
        printf("server close\n");
        /*步骤6:关闭服务器端的socket*/
        close(sockfd);
        exit(1);
    }
}

void do_service(int fd) {
    /*和客户端进行读写操作(双向通信)*/
    char buf[512];
    while (1){
        memset(buf, 0, sizeof(buf));
        size_t size;  
        if((size = read_msg(fd, buf, sizeof(buf))) < 0) {
            perror("protocal error");
            break;
        } else if(size == 0) { //客户端已经断开连接,读取到的size大小为0
            break;
        } else {
            printf("%s\n", buf);
            if(write_msg(fd, buf, sizeof(buf)) < 0) {
                if(errno == EPIPE) { //客户端读端关闭
                    break;
                }
                perror("protocal error");
            }
        }
    }
}

void out_fd(int fd) {
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    if(getpeername(fd, (struct sockaddr*)&addr, &len) < 0) {
        perror("getpeername error");
        return;
    }
    char ip[16];
    memset(ip, 0, sizeof(ip));
    int port = ntohs(addr.sin_port);
    inet_ntop(AF_INET,
                &addr.sin_addr.s_addr, ip, sizeof(ip));
    printf("%16s(%5d) closed\n", ip, port);
}

void* th_fn(void *arg) {
    int fd = *((int *)arg);
    do_service(fd);
    out_fd(fd);
    close(fd);
    return (void*)0;
}

int main(int argc, char *argv[]) {
    if (argc < 2){
        printf("usage:%s #port\n",argv[0]);
        exit(1);
    }
    
    if (signal(SIGINT, sig_handler) == SIG_ERR){
        perror("signal sigint error");
        exit(1);
    }

    /*步骤1:创建socket套接字*/
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    /*步骤2:调用bind将socket和地址绑定(包括ip,port)*/
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET; //IPV4
    serveraddr.sin_port = htons(atoi(argv[1]));
    serveraddr.sin_addr.s_addr = INADDR_ANY;
    if(bind(sockfd, (struct sockaddr *)&serveraddr,sizeof(serveraddr)) < 0) {
        perror("bind error");
        exit(1);
    }
    /*步骤3:调用listen函数启动监听(指定port监听)*/
    if(listen(sockfd,10) < 0) {
        perror("listen error");
        exit(1);
    }

    /*步骤4:调用accept函数从队列中获得一个客户端的请求连接
       注意:若没有客户端连接,调用accept函数将阻塞,直到货到衣蛾客户端连接
    */
    struct sockaddr_in clientaddr;
    socklen_t clientaddr_len = sizeof(clientaddr);

    // 设置线程属性分离
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    while (1){
        // 主控线程负责调用accept去获取客户端的连接
        int fd = accept(sockfd, NULL, NULL);
        if(fd < 0) {
            perror("accept error");
            continue;
        }

        /**
         * 步骤5:启动子线程调用IO函数(read/write)和连接的客户端进行双向的通信
        */
        pthread_t th;
        int err;
        if((err = pthread_create(&th, &attr, th_fn, (void *)&fd)) != 0) {
            perror("pthread create error");
        }    
        pthread_attr_destroy(&attr);
    }
    return 0;
}

编译服务器端:

gcc -o bin/echo_server_th -Iinclude obj/msg.o src/echo_server_mutil_th.c -lpthread

*测试

  1. 运行服务器
    ./bin/echo_server_th 8888
  2. 运行多个客户端
    ./bin/echo_client 127.0.0.1 8888
  3. 多个客户端同时向服务器发送数据,关闭其中一个客户端,不影响其他客户端,同时服务器端会打印此次关闭的客户端的ip和port。

相关文章

  • 项目中IM项目自定义协议解析说明

    IM自定义协议解析说明 IM的协议文档参见IM协议文档 一、IM协议简介 在IM的通信中,采用的是自定义的协议 +...

  • Netty笔记之八:自定义通信协议

    Netty中双方建立通信之后,对象数据会按照ByteBuf字节码的方式进行传输。 自定义一种通信协议,协议将传输数...

  • 技术帖 | dubbo源码分析 -- 远程通信 netty

    dubbo 底层通信选择了 netty 这个 nio 框架做为默认的网络通信框架并且通过自定义协议进行通信。dub...

  • 15 Netty编解码框架

    1 Netty编解码框架 在上一节中,我们提到TCP的粘包、拆包问题,可以通过自定义通信协议的方式来解决。通信协议...

  • 10月12日四期C++总结

    今天讲完了MFC的所有课程。老师给我们讲了网络通信中的TCP协议通信。讲了基于MFC的多线程编程,MFC 支持的两...

  • 远程控制-通信协议解读

    这篇文章介绍单片机与云平台的通讯协议,了解硬件和云平台的通信格数据式,以及在此协议基础上如何自定义自己的通信协...

  • Java基础知识02- 线程

    多线程通信 :什么是多线程通信 ?怎么进行通信 ? 多线程通信就是多个线程同时操作同一个全局变量,但是操作的动作不...

  • 自定义通信协议

    转自自定义通信协议 现在大部分的仪器设备都要求能过通过上位机软件来操作,这样方便调试,利于操作。其中就涉及到通信的...

  • Netty笔记之九: Netty多种通讯协议支持

    上篇文章讲解了自定义通信协议,本章节介绍如何支持多种协议。 会构建一个Server,同时支持Cat,Dog和Peo...

  • TCP、UDP、HTTP与HTTPS的异同

    TCP、UDP、HTTP与HTTPS都是通信协议,在这里首先先介绍一下什么是通信协议。 什么是通信协议? 通信协议...

网友评论

      本文标题:多线程自定义协议通信

      本文链接:https://www.haomeiwen.com/subject/tnfsfdtx.html