多线程并发服务器程序

1、server.c

#include "wrap.h"
#include <pthread.h>
#include <ctype.h>
#include <strings.h>

void *callback(void *arg)
{
    int *cfd = (int *)arg;
    printf("pthread %ld running...\n", pthread_self());
    while(1){
        char buf[BUFSIZ];
        int n = Readn(*cfd, buf, BUFSIZ);
        if (n <= 0){
            close(*cfd);
            pthread_exit(NULL);
        }
        int i = n;
        while(i--){
            buf[i] = toupper(buf[i]);
        }
        write(*cfd, buf, n);
    }
    return NULL;
}
#define SEV_PORT 3000
int main(){
    // 1、socket
    int sfd = Socket(AF_INET, SOCK_STREAM, 0);
    // 2、bind
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(SEV_PORT);
    Bind(sfd, &addr, sizeof(addr));
    // 3、listen
    Listen(sfd, 128);
    // 4、accept
    int cfds[256];
    int n = 0;
    while(1){
        struct sockaddr_in c_addr;
        socklen_t len = sizeof(c_addr);
        bzero(&c_addr, sizeof(c_addr));
        cfds[n] = Accept(sfd, &c_addr, &len);
        char buf[BUFSIZ];
        printf("Client connected -- ip:%s, port:%d\n", inet_ntop(AF_INET, &c_addr.sin_addr.s_addr, buf, BUFSIZ), ntohs(c_addr.sin_port));
        pthread_t thread;
        int ret = pthread_create(&thread, NULL, callback, cfds + n);
        if (ret < 0){
            perror("pthread create error");
            exit(1);
        }
        n++;
        pthread_detach(thread);
    }
}

wrap.h

#ifndef _WRAP_H_
#define _WRAP_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int Socket(int domain, int type, int protocol);
int Bind(int sockfd, const struct sockaddr_in *addr, socklen_t addrlen);
int Listen(int sockfd, int backlog);
int Accept(int sockfd, struct sockaddr_in *addr, socklen_t *addrlen);
int Connect(int sockfd, const struct sockaddr_in *addr, socklen_t addrlen);
ssize_t Readn(int fd, void *buf, size_t count);

#endif

wrap.c

#include "wrap.h"
#include <errno.h>
void print_err(const char* descript)
{
    perror(descript);
    exit(1);
}

int Socket(int domain, int type, int protocol)
{
    int ret = socket(domain, type, protocol);
    if (ret < 1) print_err("socket error");
    return ret;
}

int Bind(int sockfd, const struct sockaddr_in *addr, socklen_t addrlen)
{
    int ret = bind(sockfd, (struct sockaddr *)addr, addrlen);
    if (ret < 0) print_err("bind error");
    return ret;
}

int Accept(int sockfd, struct sockaddr_in *addr, socklen_t *addrlen)
{
    int sfd;
again:
    sfd = accept(sockfd, (struct sockaddr *)addr, addrlen);
    if (sfd < 0){
        // 阻塞等待,考虑被信号中断的情况
        if ((errno == ECONNABORTED) || (errno == EINTR)){
            goto again;
        }else{
            print_err("accept error");
        }
    }
    return sfd;
}

int Listen(int sockfd, int backlog)
{
    int ret = listen(sockfd, backlog);
    if (ret < 0) print_err("listen error");
    return ret;
}

int Connect(int sockfd, const struct sockaddr_in *addr, socklen_t addrlen)
{
    int ret = connect(sockfd, (struct sockaddr *)addr, addrlen);
    if (ret < 0) print_err("connect error");
    return ret;
}

ssize_t Readn(int fd, void *buf, size_t count)
{
    size_t readed = 0;// 已读数
    size_t remain = count;// 未读数
    while(remain > 0){
        int n = read(fd, buf+readed, remain);
        if (n < 0){    // 异常处理
            if (errno == EINTR){
                n = 0;// 信号中断,继续循环
            }else{
                return n;// 异常情况直接返回
            }
        }else if (n < remain){
            remain -= n;
            break;
        }
        readed += n;
        remain -= n;
    }
    return count - remain;// 返回应读数-未读数
}

运行结果:

parallels@ubuntu:~/Linux/mp-socket$ ./server.out
Client connected -- ip:10.211.55.2, port:49543
Client connected -- ip:10.211.55.2, port:49546
^C
parallels@ubuntu:~/Linux/mp-socket$

2、client.c

#include "wrap.h"
#include <unistd.h>
#include <string.h>

#define SERVER_PORT 3000
#define SERVER_IP "10.211.55.6"
int main(){
    int sfd = Socket(PF_INET, SOCK_STREAM, 0);

    struct sockaddr_in svr_addr;
    svr_addr.sin_family = PF_INET;
    svr_addr.sin_port = htons(SERVER_PORT);
    // 清0操作
    memset(&svr_addr.sin_addr.s_addr, 0, sizeof(svr_addr.sin_addr.s_addr));
    // 将点分十进制字符串转为字节序
    inet_pton(PF_INET, SERVER_IP, &svr_addr.sin_addr.s_addr);
    // 发起网络连接
    Connect(sfd, &svr_addr, sizeof(svr_addr));
    printf("服务器连接成功!\n");
    char buf[BUFSIZ];
    while(1){
        // 读取输入流
        fgets(buf, sizeof(buf), stdin);
        // 写入套接字
        write(sfd, buf, strlen(buf));
        // 读取服务器响应
        int n = read(sfd, buf, sizeof(buf));
        // 将结果输出到标准输出流
        write(STDOUT_FILENO, buf, n);
    }
    close(sfd);
    return 0;
}

运行结果

yusian@SianMac2:~/Linux/socket$ ./client.out
服务器连接成功!
asdf
ASDF
^C
yusian@SianMac2:~/Linux/socket$

Leave a Reply