多线程并发服务器

多线程并发服务器

服务端

#include <stdio.h>
#include <string.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <pthread.h>
#define PORT 8888
#define BUFFSIZE 1024
#define ERRORCODE -1

void *RW_Work(void *arg)
{
    int *afd = (int *)arg;
    while (1)
    {
        int i;
        char recv_buf[BUFFSIZE];

        int n = read(*afd, recv_buf, sizeof(recv_buf));
        if (n == 0)
        {
            perror("connect interrupt");
            break;
        }
        fputs(recv_buf, stdout);
        for (i = 0; i < n; i++)
        {
            recv_buf[i] = toupper(recv_buf[i]);
        }
        write(*afd, recv_buf, sizeof(recv_buf));
    }
    close(*afd);
    pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
    char buf[BUFSIZ], client_addr_INFO[BUFFSIZE];
    int accept_fd, listen_fd;
    socklen_t client_len;
    struct sockaddr_in listen_addr, accept_addr;
    char buffer[BUFFSIZE];
    int buffer_len, i;
    int on = 1;
    pthread_t tid;
    // 创建socket
    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd == -1)
    {
        printf("创建socket error: %s \n", strerror(errno));
        return ERRORCODE;
    }
    // bind
    if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
    {
        printf("setsockopt error: %s \n", strerror(errno));
        return ERRORCODE;
    }
    listen_addr.sin_family = AF_INET;
    listen_addr.sin_port = htons(PORT);
    listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(listen_fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0)
    {
        printf("bind error: %s \n", strerror(errno));
        return ERRORCODE;
    }

    // listen
    if (listen(listen_fd, 5) == -1)
    {
        printf("listen error: %s \n", strerror(errno));
        return ERRORCODE;
    }
    printf("服务端创建成功,等待连接\n");
    // accept

    while (1)
    {
        client_len = sizeof(accept_addr);

        /* code */
        accept_fd = accept(listen_fd, (struct sockaddr *)&accept_addr, &client_len);
        if (accept_fd == -1)
        {
            printf("accept error: %s \n", strerror(errno));
            return ERRORCODE;
        }
        printf("accept ip : %s,port : %d\n",
               inet_ntop(AF_INET, &accept_addr.sin_addr.s_addr, client_addr_INFO, sizeof(client_addr_INFO)),
               ntohs(accept_addr.sin_port));
        //printf("accept ip : %s,port : %d\n", inet_ntoa(accept_addr.sin_addr), ntohs(accept_addr.sin_port));

        pthread_create(&tid, NULL, RW_Work, (void *)&accept_fd);
        pthread_detach(tid);
    }
    //close(accept_fd);
    close(listen_fd);
    return 0;
}

代码运行

在这里插入图片描述
为什么线程库需要在编译时显式链接,而其它的库不需要呢?

因为多线程的支持通常在运行时才需要,因此需要在链接时特别指定。

这就要说到大多数标准C或C++库(如libc、libstdc++)在编译器启动时就自动被链接了。

线程创建

创建时机

服务端在accept成功之后,创建一个线程,将接收到的accept_fd交给线程处理,线程通过这个accept_fd与客户端进行读写操作。

创建线程函数原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
参数意义
pthread_t *thread

指向线程标识符的指针

const pthread_attr_t *attr

const pthread_attr_t *attr:一个指向pthread_attr_t类型对象的指针,用于设置线程属性。如果值为NULL,则使用默认属性。通过修改这个属性对象,可以改变新线程的某些特性,如堆栈大小、调度参数等

void *(*start_routine) (void *)

指向线程运行函数的指针。这个函数是新线程的入口点,它接受一个指向void的指针作为参数,通常用于传递线程所需的数据

void *arg

传递给start_routine函数的参数。这个参数可以是任何类型,但在调用start_routine时,它会被转换为void *类型

函数功能描述

The  pthread_create()  function  starts  a  new  thread  in the calling
       process.  The new thread starts execution by invoking  start_routine();
       arg is passed as the sole argument of start_routine().

这个函数总体来说是在一个正在调用的进程中创建一个新的线程,而这个线程会invoking(借助)所指定的start_routine(函数),arg作为这个函数的唯一参传递给start_routine。

函数返回值

On  success,  pthread_create() returns 0; on error, it returns an error
       number, and the contents of *thread are undefined.

这个意思就是说成功创建会返回0,失败会返回一个错误代码,这是一个int型数据,不同的数字代表了不同的错误类型。

错误代码

例如:
EAGAIN:通常是11号错误,表示“资源暂时不可用”,在这个上下文中,它指的是无法创建新线程因为资源限制。
EINVAL:通常是22号错误,表示“无效的参数”,意味着某个函数调用传递了一个无效的参数。
EPERM:通常是1号错误,表示“操作不允许”,通常用于表示没有足够的权限执行某个操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值