前面的服务端只能在同一时间内处理一个客户端请求,而另外发起连接的客户端则会阻塞在accept队列中,等待正在服务的客户端退出直到轮到自己。这种仅能一对一处理的服务器在效率上是绝不可允许的,因此我们需要使得服务器能同时实现对多个用户的服务处理。
本文介绍第一种方法:阻塞IO+多线程并发(进程开销过大,不予考虑)
其原理在于server使用accpet轮询,得到客户端的套接字后交付给一个线程处理,之后重复轮询accept。

服务端
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/ioctl.h>

unsigned short server_Port = 1234; // 服务器端口
const char *IP = "192.168.80.132"; // 服务器IP

typedef struct client_info
{
    struct sockaddr_in client_Addr;
    int conn_Scoket;
} client_info;

/*字母转大写*/
void upper(char *buf)
{
    char *pointer = buf;
    while (*pointer != '\n')
    {
        if (*pointer >= 'a' && *pointer <= 'z')
            *pointer -= 32;
        pointer++;
    }
    return;
}

void handle_client(void *arg)
{
    client_info client = *(client_info *)arg;
    char *client_Ip = inet_ntoa(client.client_Addr.sin_addr);
    int conn_Socket = client.conn_Scoket;
    in_port_t client_Port = ntohs(client.client_Addr.sin_port);
    printf("客户端: %s:%hu已连接!\n", client_Ip, client_Port);
    while (1)
    {

        char buf[100];
        memset(buf, '\0', 100);
        int count = read(conn_Socket, buf, 99);
        if (count == -1) // 若未有数据则返回报错
        {
            continue;
        }
        else if (count == 0)
        {
            printf("客户端: %s:%hu断开连接!\n", client_Ip, client_Port);
            close(conn_Socket);
            break;
        }
        else
        {
            printf("客户端: %s:%hu消息:%s", client_Ip, client_Port, buf);
            upper(buf);
            write(conn_Socket, buf, 99);
        }
    }
}

int main()
{
    // 创建套接字
    int server_Socket = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_Addr;
    server_Addr.sin_family = AF_INET;
    server_Addr.sin_port = htons(server_Port);
    int flag = inet_aton(IP, &(server_Addr.sin_addr));
    if (!flag)
    {
        perror("IP transfer failed!\n");
    }

    // 绑定服务器IP地址端口号
    bind(server_Socket, (struct sockaddr *)&server_Addr, sizeof(server_Addr));
    listen(server_Socket, 5);

    while (1)
    {
        client_info client;
        int addrlen = sizeof(struct sockaddr_in);
        int conn_Socket = accept(server_Socket, (struct sockaddr *)&(client.client_Addr), &addrlen);
        if (conn_Socket == -1)
        {
            break;
        }
        /*创建一个新线程*/
        pthread_t new_thread;
        client.conn_Scoket = conn_Socket;
        pthread_create(&new_thread, NULL, handle_client, (void *)&client);
        pthread_detach(new_thread);
    }
    pthread_exit(NULL); // 等待处理客户端的子线程完结后才退出
    close(server_Socket);
    return 0;
}

客户端可用第一篇

posted on 2023-04-30 16:45  Aspirants  阅读(136)  评论(0)    收藏  举报