socket利用多线程实现一对多通信

时间:2024-03-06 15:02:21

1、服务器端:socket()建立套接字,绑定(bind)并监听(listen),用accept()等待客户端连接。将accept()写入死循环,每次连接一个客户端,开一个线程。

2、一般情况下建立socket连接后服务器与客户端建立了一个管道,当关闭socket或关闭客户端的时候,会导致管道破裂信号。如果使用默认处理则会导致服务器程序退出。

需要程序忽略管道破裂信号。

signal(SIGPIPE, SIG_IGN);//忽略管道破裂信号

3、线程处理完毕后,需要及时关闭线程,通过recv()函数的特性,在socket关闭的时候返回零。判断并结束线程。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>  //处理信号问题 应忽略socket 信号

#define MY_IP     "192.168.149.137"
#define MY_PORT  5005
#define BACKLOG  100

#define DEBUF(X) printf(X)
int fd = -1;
char buf[100];    //最大连接数
void *func(void *arg)
{    char recv_buf[100];
    char send_buf[100];
    int client_fd = (int)arg;//传参
    int ret = 1;
    memset(recv_buf,0,sizeof(recv_buf));
    while(1)
    {
        ret = recv(client_fd,&recv_buf,sizeof(recv_buf),0);
        if(0 == ret) break;//阻塞等待过程中断开则会返回0
        printf("%s\n",recv_buf); 
        send(client_fd,&recv_buf,sizeof(recv_buf),0);
        memset(recv_buf,0,sizeof(recv_buf));        
    }
    printf("over \n");
}
 int main()
{    
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;//客户地址
    socklen_t len = 0;//接收长度
    char recv_buf[100];
    char send_buf[100];
    int sock_fd = -1;//监听描述符
    int client_fd = -1;//连接fd

    int ret = -1;
    pthread_t th =-1 ;
    
    signal(SIGPIPE, SIG_IGN);//忽略管道破裂信号
    sock_fd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sock_fd)
    {
        perror("socket");
        return -1;
    }
    printf("sock_fd = %d.\n",sock_fd);
    //2.bind绑定socket 和本机IP 端口
    server_addr.sin_family = AF_INET;//IPV4
    server_addr.sin_port = htons(MY_PORT);//设置端口模式
    server_addr.sin_addr.s_addr = inet_addr(MY_IP);//设置IP
    ret = bind(sock_fd,(struct  sockaddr  *)&server_addr,sizeof(server_addr));
    if(-1 == ret)
    {
        perror("bind");
        return -1;
    }
    DEBUF("bind ok\n");
    //3.listen 设 置监听
    ret = listen(sock_fd, BACKLOG);//BACKLOG为排队处理
    if(-1 == ret)
    {
        perror("listen");
        return -1;
    }
    DEBUF("listen ok\n");
    while(1)
    {
        client_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &len);
        if(-1 == client_fd)
        {
            perror("listen");
            return -1;
        }
        ret = pthread_create(&th ,NULL , func , (void*)client_fd);//创建线程
        DEBUF("新用户加入\n");
         if(ret != 0)
        {
            printf("pthread_create error \n");
            return -1;
        } 
    }
    return 0;
}