Linux 网络编程2 TCP并发服务器

Linux 网络编程学习 TCP/IP网络编程2


在前面TCP网络编程代码的基础上进行改造,实现并发服务器功能。

TCP多线程服务器

实现功能:

  • server端可以绑定在任意IP端
  • server端停止使用crtl+p
  • client端运行./client时需加上(ip_addr, netport)
  • 支持多client链接
  • server端可打印client的ip地址和端口号

server端代码

#include "net.h"
#include <pthread.h>

typedef struct client_info{
    int newfp;
    char ipv4_addr[14];
    int port;
}Client_info, *pClient_info ;

void * process(pClient_info arg);
int main()
{
    int fp;
    struct sockaddr_in myaddr;
    // 1. open socket
    if((fp = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket fail");
        exit(0);
    }

    // 2. set bind()
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(Netport);
    // inet_aton(Netip,(int_addr *)&myaddr.sin_addr.s_addr);
    //myaddr.sin_addr.s_addr = inet_addr(Netip);
    //优化,使服务器能够接受绑定在任意IP上 INADDR_ANY
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(fp,(struct sockaddr*) &myaddr,sizeof(myaddr)) < 0)
    {
        perror("bind fail");
        exit(0);
    }

    // 3. set listen()
    if(listen(fp, BACKLOG) < 0)
    {
        perror("listen fail");
        exit(0);
    }  
 
    // 4. set accept()
    int newfp = -1;
    struct sockaddr_in recv_addr;
    socklen_t recv_addr_len = sizeof(recv_addr);
    while(1)
    {
        newfp = accept(fp, (struct sockaddr *)&recv_addr, (socklen_t *)&recv_addr_len);
        if(newfp < 0)
        {
            perror("accept fail");
            exit(0);
        }
        Client_info cin;
        bzero(cin.ipv4_addr, 16);
        if(NULL == inet_ntop(AF_INET,(void *)&recv_addr.sin_addr, cin.ipv4_addr, sizeof(recv_addr)))
        {
            perror("inet_ntop");
            exit(0);
        }
        cin.port = ntohs(recv_addr.sin_port);
        cin.newfp = newfp;
        printf("success the connet !\n");
        printf("connect ip address = %s, connect port = %d \n",cin.ipv4_addr, cin.port);

        pthread_t  tid;
        if(pthread_create(&tid, NULL, (void *)(process), &cin) != 0)
        {
            perror("thread fail");
            exit(0);
        }


    }  
    // 5. set close
    close(newfp);
    close(fp);

    return 0;

}

void * process(pClient_info cin)
{
    pthread_detach(pthread_self());  //线程分离
    int newfp = cin->newfp;
    char ipv4_addr[16] = {0};
    strcpy(ipv4_addr, cin->ipv4_addr);
    int port = cin->port;

    char buf[BUFSIZ];
    bzero(buf,BUFSIZ);
    int ret = -1;
    while(1)
    {
        do{
            ret = read(newfp, buf, BUFSIZ-1);
        }while(ret<0 && errno == EINTR);   //没有接受到数据,继续读取
        if(ret < 0)
        {
            perror("read fail");
            exit(1);
        }
        if(ret == 0)        //读取结束
        {
            break;
        }
        if(!strncmp(buf,QUIT_STR,strlen(QUIT_STR)))
        {
            printf("Client is exiting !\n");
            break;
        }
        if(!strncmp(buf,"\n",1))
        {
            bzero(buf,BUFSIZ);
        }
        printf("(%s : %d): %s \n", ipv4_addr, port,buf);
    }
    close(newfp);
    pthread_exit(NULL);     //线程结束
    pthread_join(pthread_self(),NULL);

    return NULL;
}

client端代码

#include "net.h"

int main(int argc, char* argcv[])
{
    if(argc != 3)
    {
        printf("enter error!\n");
        printf("please fill:ip_addr, netport \n");
        exit(0);
    }
    // 1. set 
    int fp = -1;
    if((fp = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket fail");
        exit(0);
    }

    // 2.set connect
    struct sockaddr_in myaddr;
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    int netport = atoi(argcv[2]);
    if(netport < 50000)
    {
        netport = Netport;
    }
    myaddr.sin_port = htons(netport);
    //myaddr.sin_addr.s_addr = inet_addr(Netip);
    if(inet_pton(AF_INET, argcv[1], (void *)&myaddr.sin_addr.s_addr) != 1)
    {
        perror("inet_pton fail");
        exit(0);
    }

    if(connect(fp,(struct sockaddr *)&myaddr, sizeof(myaddr)) < 0)
    {
        perror("connect fail");
        exit(0);
    }
    // 3. set read
    char buf[BUFSIZ];
    while(1)
    {
        bzero(buf,BUFSIZ);
        if(fgets(buf, BUFSIZ, stdin) == NULL)
        {
            continue;
        }
        write(fp, buf, strlen(buf));
        if(!strncmp(buf,QUIT_STR, strlen(QUIT_STR)))
        {
            printf("Client is exiting !\n");
            break;
        }
    }

    close(fp);

    return 0;
}

net.h头文件

#ifndef  __NET_H__
#define  __NET_H__

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>  
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define Netport 50001
#define Netip "XXX.XXX.XXX.XXX"  //ipv4地址
#define BACKLOG 5
#define QUIT_STR "quit"


#endif

TCP多进程服务器

server端
采用SIGCHLD信号来回收子进程。

#include "net.h"
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>

typedef struct client_info{
    int newfp;
    char ipv4_addr[14];
    int port;
}Client_info, *pClient_info ;

void * process(pClient_info arg);
void cil_data_handle(int signum);

int main()
{
    signal(SIGCHLD, cil_data_handle);
    int fp;
    struct sockaddr_in myaddr;
    // 1. open socket
    if((fp = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket fail");
        exit(0);
    }

    // 2. set bind()
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(Netport);
    // inet_aton(Netip,(int_addr *)&myaddr.sin_addr.s_addr);
    //myaddr.sin_addr.s_addr = inet_addr(Netip);
    //优化,使服务器能够接受绑定在任意IP上 INADDR_ANY
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(fp,(struct sockaddr*) &myaddr,sizeof(myaddr)) < 0)
    {
        perror("bind fail");
        exit(0);
    }

    // 3. set listen()
    if(listen(fp, BACKLOG) < 0)
    {
        perror("listen fail");
        exit(0);
    }  
 
    // 4. set accept()
    int newfp = -1;
    struct sockaddr_in recv_addr;
    socklen_t recv_addr_len = sizeof(recv_addr);
    while(1)
    {
        newfp = accept(fp, (struct sockaddr *)&recv_addr, (socklen_t *)&recv_addr_len);
        if(newfp < 0)
        {
            perror("accept fail");
            exit(0);
        }
        Client_info cin;
        bzero(cin.ipv4_addr, 16);
        if(NULL == inet_ntop(AF_INET,(void *)&recv_addr.sin_addr, cin.ipv4_addr, sizeof(recv_addr)))
        {
            perror("inet_ntop");
            exit(0);
        }
        cin.port = ntohs(recv_addr.sin_port);
        cin.newfp = newfp;
        printf("success the connet !\n");
        printf("connect ip address = %s, connect port = %d \n",cin.ipv4_addr, cin.port);

        // pthread_t  tid;
        // if(pthread_create(&tid, NULL, (void *)(process), &cin) != 0)
        // {
        //     perror("thread fail");
        //     exit(0);
        // }
        pid_t pid;
        if((pid = fork()) < 0 )
        {
            perror("fork fail");
            exit(0);
        }
        else if(pid == 0)       //子进程
        {
            close(fp);
            process(&cin);
            return 0;
        }
        else                    // 父进程
        {
            close(newfp);
        }


    }  
    // 5. set close
    close(fp);

    return 0;

}

void * process(pClient_info cin)
{
    pthread_detach(pthread_self());  //线程分离
    int newfp = cin->newfp;
    char ipv4_addr[16] = {0};
    strcpy(ipv4_addr, cin->ipv4_addr);
    int port = cin->port;

    char buf[BUFSIZ];
    bzero(buf,BUFSIZ);
    int ret = -1;
    while(1)
    {
        do{
            ret = read(newfp, buf, BUFSIZ-1);
        }while(ret<0 && errno == EINTR);   //没有接受到数据,继续读取
        if(ret < 0)
        {
            perror("read fail");
            exit(1);
        }
        if(ret == 0)        //读取结束
        {
            break;
        }
        if(!strncmp(buf,QUIT_STR,strlen(QUIT_STR)))
        {
            printf("Client is exiting !\n");
            break;
        }
        if(!strncmp(buf,"\n",1))
        {
            bzero(buf,BUFSIZ);
        }
        printf("(%s : %d): %s \n", ipv4_addr, port,buf);
    }
    close(newfp);
    
    return NULL;
}

void cil_data_handle(int signum)
{
    if(signum == SIGCHLD)
    {
        waitpid(-1, NULL, WNOHANG);
    }
}


client端

#include "net.h"

int main(int argc, char* argcv[])
{
    if(argc != 3)
    {
        printf("enter error!\n");
        printf("please fill:ip_addr, netport \n");
        exit(0);
    }
    // 1. set 
    int fp = -1;
    if((fp = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket fail");
        exit(0);
    }

    // 2.set connect
    struct sockaddr_in myaddr;
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    int netport = atoi(argcv[2]);
    if(netport < 50000)
    {
        netport = Netport;
    }
    myaddr.sin_port = htons(netport);
    //myaddr.sin_addr.s_addr = inet_addr(Netip);
    if(inet_pton(AF_INET, argcv[1], (void *)&myaddr.sin_addr.s_addr) != 1)
    {
        perror("inet_pton fail");
        exit(0);
    }

    if(connect(fp,(struct sockaddr *)&myaddr, sizeof(myaddr)) < 0)
    {
        perror("connect fail");
        exit(0);
    }
    // 3. set read
    char buf[BUFSIZ];
    while(1)
    {
        bzero(buf,BUFSIZ);
        if(fgets(buf, BUFSIZ, stdin) == NULL)
        {
            continue;
        }
        write(fp, buf, strlen(buf));
        if(!strncmp(buf,QUIT_STR, strlen(QUIT_STR)))
        {
            printf("Client is exiting !\n");
            break;
        }
    }

    close(fp);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值