【TCP】并发服务器<线程>

发布时间 2023-12-14 21:16:13作者: 素装写淡定
// 并发服务器-线程
#include <stdio.h>
#include <strings.h>    //bzero
#include <unistd.h>     //close
#include <sys/socket.h> //socket
#include <netinet/in.h> //struct sockaddr_in
#include <arpa/inet.h>  //inet_addr
#include <string.h>
#include <pthread.h>

void *recv_send_fun(void *arg)
{
    int sockfd_new = *((int *)arg);
    char buf[1024] = "";
    while (1)
    {
        bzero(buf, sizeof(buf));
        recv(sockfd_new, buf, sizeof(buf), 0);
        printf("recv: %s\n", buf);
        send(sockfd_new, "ok", sizeof("ok"), 0);
        if (strcmp(buf, "quit") == 0)
            break;
        // 如果收到了0长度的数据包,意思客户端断开连接,子进程结束
        if (strlen(buf) == 0)
            break;
    }
    return NULL;
}

int main(int argc, char const *argv[])
{
    // 1.创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket");
        return -1;
    }
    // 端口复用
    int yes = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
    // 2.绑定bind
    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(8000);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 机器的所有可用IP地址
    int ret = bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
    if (ret != 0)
    {
        perror("bind");
        return -1;
    }
    // 3.监听
    int backlog = 10;
    ret = listen(sockfd, backlog);
    if (ret < 0)
    {
        perror("listen");
        return -1;
    }
    // 4.提取,等待一个客户端连接
    struct sockaddr_in cli_addr;
    socklen_t len = sizeof(cli_addr);

    char ip[16] = "";
    int sockfd_new = 0;
    while (1)
    {
        // 保证提取到了正确的客户端,而不是被信号打断
        while (1)
        {
            sockfd_new = accept(sockfd, (struct sockaddr *)&cli_addr, &len);
            if (sockfd_new > 0)
                break;
        }
        inet_ntop(AF_INET, (void *)&cli_addr.sin_addr, ip, 16);
        printf("提取到的客户端: %s--->%hu\n", ip, ntohs(cli_addr.sin_port)); // ip port
        // 5.创建线程
        pthread_t pth;
        pthread_create(&pth, NULL, recv_send_fun, (void *)&sockfd_new);
        pthread_detach(pth);
    }

    // 6.关闭套接字
    close(sockfd_new);
    close(sockfd);
    return 0;
}