最简单的多进程/多线程服务器代码

给群里朋友写的 . *nix 下:

一个多进程 一个多线程 , 没太多意义的代码 ,只是简单收发, 没有处理粘包这一类问题,util.h中有实现;

 

util.h

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <signal.h>



#define EPOLL_SIZE 64
#define PORT 9988
#define BACKLOG 10
#define MAXLINE 4096
#define SA struct sockaddr
ssize_t readn(int fd , void *ptr, size_t n)
{
    size_t left = n;
    char * p = (char *)ptr;
    int nread = 0;
    while (left > 0){
        if((nread = read(fd,p,left)) < 0){
                if(errno == EINTR)
                    nread = 0;
                else
                    return -1;
        }
        else if(nread == 0)
            break;
        left -= nread;
        p += nread;
    }
    return n - left;
}
ssize_t writen(int fd , void * ptr , size_t n)
{
    size_t left = n;
    char * p = (char*)ptr;
    int nwrite = 0;
    while( left > 0){
        if((nwrite = write(fd,p,left)) <= 0){
            if(errno == EINTR && nwrite < 0)
                nwrite = 0;
            else
                return -1;
        }
        left -= nwrite;
        p += nwrite;
    }
    return n - left;
}

int conn_timeout(int sockfd , const struct sockaddr_in * sin, socklen_t socklen, int secs)
{
    int old_flag = fcntl(sockfd,F_GETFL,0);
    if( fcntl(sockfd,F_SETFL,old_flag|O_NONBLOCK) < 0){
        perror("fcntl failed");
        return -1;
    }

    int ret = 0;
    if((ret = connect(sockfd,(SA*)&sin,socklen)) < 0){
        if(errno != EINPROGRESS){
            perror("connect error");
            return -1;
        }
    }
    if(0 == ret)
        goto done;

    fd_set rset,wset;
    FD_ZERO(&rset);
    FD_SET(sockfd,&rset);
    wset = rset;
    struct timeval timeout;
    timeout.tv_sec= secs;
    timeout.tv_usec = 0;
    ret = select(sockfd+1,&rset,&wset,NULL,secs?&timeout:NULL);
    if(ret < 0){
        perror("select error");
        return -1;
    }
    else if( 0 == ret){
        close(sockfd);
        return -1;
    }
    if(!(FD_ISSET(sockfd,&rset) || FD_ISSET(sockfd,&wset))){
        return -1;
    }
    done:
    fcntl(sockfd,F_SETFL,old_flag);
    return 0;
}

 

 

多进程:

#include "util.h"

// sig handler;
void wait_children(int sig)
{
    while ( waitpid(-1,0,WNOHANG) > 0 );
}

int main(int argc, char ** argv)
{
    signal(SIGCHLD , wait_children);

    //init socket
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serv_addr , clt_addr;
    memset(&serv_addr ,0, sizeof(serv_addr));
    memset(&clt_addr ,0, sizeof(clt_addr));
    serv_addr.sin_port = PORT;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_family = AF_INET;

    if ( bind(listenfd , (SA *)&serv_addr, sizeof(serv_addr)) < 0 ){
        perror("bind");
        return 0;
    }

    if( listen(listenfd ,BACKLOG) < 0){
        perror("listen");
        return 0;
    }

    socklen_t  clt_len  = 0;
    int connfd = -1;
    pid_t pid = 0;
    while(1){
        clt_len = sizeof(clt_addr);
        connfd = accept(listenfd,(SA*)&clt_addr, &clt_len);
        pid = fork();
        if( pid > 0 ){
            //parent
            close(connfd);
        }
        else if(0 == pid ){
            //child
            close(listenfd);
            char buff[20];
            int len = 0;
            while(1) {
                len = read(connfd, buff, 19);
                if(len < 0){
                    perror("read error");
                    break;
                }
                else if ( 0 == len){
                    printf(" clt sock : %d , closed!\n" , connfd);
                    break;
                }
                buff[len] = 0;
                printf("serv: read data: %s\n" , buff);
                write(connfd, buff,len);
            }
            close(connfd);
            return 0;
        }
        else
        {
            //如果失败了
            perror("fork");
            close(connfd);
            continue;
        }

    }
    return 0;
}

 

多线程:


#include "util.h"
typedef struct __client_info{
    int clientfd;
    pthread_t tid;
    struct sockaddr_in si;
} client_info;
static void * client_thread(void*);
static int copy_client_info(client_info *,struct sockaddr_in *);
int main(int argc ,char ** argv)
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    int clientfd = 0;
    struct sockaddr_in si = {0} , client = {0};
    si.sin_family = AF_INET;
    si.sin_addr.s_addr = INADDR_ANY;
    si.sin_port = htons(PORT);

    socklen_t  addr_len = sizeof(si);
    if(bind(sockfd,(SA*)&si,addr_len) < 0){
        perror("bind failed");
        return 0;
    }
    listen(sockfd,BACKLOG);
    socklen_t  client_len = 0;
    while(1){
        client_len = sizeof(client);
        clientfd = accept(sockfd,(SA*)&client,&client_len);
        client_info *pinfo = malloc(sizeof(client_info));
        pinfo->clientfd = clientfd;
        copy_client_info(pinfo,&client);
        pthread_create(&pinfo->tid,NULL,client_thread,pinfo);
    }
    return  0;
}
static int copy_client_info(client_info *target,struct sockaddr_in *src)
{
    if(!target || !src)
        return -1;
    target->si.sin_port = src->sin_port;
    target->si.sin_addr.s_addr = src->sin_addr.s_addr;
    target->si.sin_family = src->sin_family;
    return 0;
}
static void * client_thread(void * param)
{
    pthread_detach(pthread_self());
    client_info * info = (client_info*)param;
    char ip[16] = {0} ;
    ssize_t iplen = sizeof(ip);
    char buf[MAXLINE] = {0};
    printf("connect from : %s ,port:%d ,clientfd:%d, tid:%ld\n",
           inet_ntop(AF_INET,&info->si.sin_addr.s_addr,ip,iplen)
            ,ntohs(info->si.sin_port),info->clientfd,info->tid);
    int nread = 0;
    while(1){
        nread = read(info->clientfd,buf,MAXLINE);
        if(nread<=0){
            break;
        }
        if(buf[0] == 'q') break;
        write(info->clientfd,buf,nread);
    }
    close(info->clientfd);
    free(info);
    puts("a client quit");
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值