网络编程(4)-----TCP并发服务器多线程编程

多线程TCP编程:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netint/ip.h>
#include <errno.h>
#include <pthread.h>


void usage(char *s)
{
    printf("%s serv_ip serv_port",s);
    printf("\n\t serv_ip: server ip address");
    printf("\n\t serv_port: server port(>5000)\n\t");

}


#define SERV_PORT 5001
#define SERV_IP_ADDR "192.168.7.246"  //服务器地址
#define BACKLOG 5                     //backlog同时允许几路客户端和服务器进行正在连接的过程(正在三次握手)一般填5,测试得知,ARM最大为8
#define QUIT_STR  "quit"
int  main(int argc,char **argv)
{
   int fd =-1;
   short port;
   struct socke_in sin;
   if(argc != 3)
    {
        usage(argv[0]);
exit(1);
    }
    port = atoi(argv[2]);
    if(port<5000) 
    {
        usage(argv[0]);
        exit(1);
    }


   /*1.创建socket fd*/
   if((fd = socket(AF_INET,SOCK_STREAM,0))<0)
   {
        perror("socket");
        exit(1);
    }
  /*优化4:允许绑定地址快速重用*/
      int b_reuse = 1;
      setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));

    /*2绑定*/
    /*2.1填充struct sockaddr_in结构体变量*/
    bzero(&sin,sizeof(sin));
    sin.sin_family = AF_INET;   //IPV4
    sin.sin_port = htons(port);   //网络字节序的端口号
/*优化1:让服务器程序能绑定在任意的IP上*/
#if 1
    sin.sin_addr.s_addr = hton1(INADDY_ANY);  //点分形式的IP地址,结果为#32整数
#else
    if(inet_pton(AF_INET,argv[1],(void *)&sin.sin_addr.s_addr)!=1)
    {
       perror("inet_pton");
       exit(1);
    }
#endif
     /*2.2绑定*/
    if(bind(fd,(struct sockaddr *)&sin,sizeof(sin)) < 0 )
    {
           perror("bind");
           exit(1);
     }  
    //如果是IPV6编程呢个,要使用struct sockaddr_in6结构体(详细情况请参考man 7 ipv6 ),通常更通用的方法可以通过struct sockaddr_storage来编程
 
    /*3.调用listen()把主动套接字变成被动套接字*/
    
    if(listen(fd,BACKLOG)<0)
    {
        perror("listen");
        exit(1);
 
   }                
    /*4.阻塞等待客户端连接请求*/


   /*优化3:用多进程/多线程处理已经建立好连接的客户端数据*/
   pthread_t tid;
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
   while(1){
      if((newfd = accept(fd,(struct sockaddr *)&cin,&addrlen))< 0)
        {
            perror("accept");
            exit(1);
        }
       char ipv4_addr[16];
       if(!inet_ntop(AF_INET,(void * )&cin.sin_addr,ipv4_addr,sizeof(cin))){
        perror("inet_ntop");
        exit(1);
    }
    printf("client(%s:%d)  is connected!",ipv4_addr,htons(cin.sin_port));
    pthread_create(&tid,NULL,(void *)cli_data_handle,(void *)&newfd);

}

   close(fd);
   return 0;
}

void cli_data_handle(void * arg)
{
    int newfd = *(int *)arg;
    printf("handler thread: newfd = %d\n",newfd);
    int ret = -1;
    char buf[BUFSIZ];
    while(1){
        bzero(buf,BUFSIZ);
        do{
            ret = read(newfd,buf,BUFSIZ-1);
         }while(ret<0 &&EINTR == errno);
        if(ret < 0)
        {
            perror("read");
            exit(1);
        }
        if(!ret)  //对方已关闭
        {
            break;
        }
    }




}

 多进程TCP:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netint/ip.h>
#include <errno.h>
#include <pthread.h>


void usage(char *s)
{
    printf("%s serv_ip serv_port",s);
    printf("\n\t serv_ip: server ip address");
    printf("\n\t serv_port: server port(>5000)\n\t");

}


#define SERV_PORT 5001
#define SERV_IP_ADDR "192.168.7.246"  //服务器地址
#define BACKLOG 5                     //backlog同时允许几路客户端和服务器进行正在连接的过程(正在三次握手)一般填5,测试得知,ARM最大为8
#define QUIT_STR  "quit"

void cli_data_handle(void *arg);
void sig_child_hanle(int signo)
{
       if(SIGCHLD == signo)
       {
            waitpid(-1,NULL,WNOHANG);
       }


}






int  main(int argc,char **argv)
{
    int fd =-1;
    short port;
    struct socke_in sin;
    signal(SIGCHLD,sig_child_handle);






   if(argc != 3)
    {
        usage(argv[0]);
exit(1);
    }
    port = atoi(argv[2]);
    if(port<5000) 
    {
        usage(argv[0]);
        exit(1);
    }


   /*1.创建socket fd*/
   if((fd = socket(AF_INET,SOCK_STREAM,0))<0)
   {
        perror("socket");
        exit(1);
    }
  /*优化4:允许绑定地址快速重用*/
      int b_reuse = 1;
      setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));

    /*2绑定*/
    /*2.1填充struct sockaddr_in结构体变量*/
    bzero(&sin,sizeof(sin));
    sin.sin_family = AF_INET;   //IPV4
    sin.sin_port = htons(port);   //网络字节序的端口号
/*优化1:让服务器程序能绑定在任意的IP上*/
#if 1
    sin.sin_addr.s_addr = hton1(INADDY_ANY);  //点分形式的IP地址,结果为#32整数
#else
    if(inet_pton(AF_INET,argv[1],(void *)&sin.sin_addr.s_addr)!=1)
    {
       perror("inet_pton");
       exit(1);
    }
#endif
     /*2.2绑定*/
    if(bind(fd,(struct sockaddr *)&sin,sizeof(sin)) < 0 )
    {
           perror("bind");
           exit(1);
     }  
    //如果是IPV6编程呢个,要使用struct sockaddr_in6结构体(详细情况请参考man 7 ipv6 ),通常更通用的方法可以通过struct sockaddr_storage来编程
 
    /*3.调用listen()把主动套接字变成被动套接字*/
    
    if(listen(fd,BACKLOG)<0)
    {
        perror("listen");
        exit(1);
 
   }                
    /*4.阻塞等待客户端连接请求*/

# if 0 
   /*优化3:用多进程/多线程处理已经建立好连接的客户端数据*/
   pthread_t tid;
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
   while(1){
        pid_t pid = -1;
      if((newfd = accept(fd,(struct sockaddr *)&cin,&addrlen))< 0)
        {
            perror("accept");
            exit(1);
        }
       char ipv4_addr[16];
       if(!inet_ntop(AF_INET,(void * )&cin.sin_addr,ipv4_addr,sizeof(cin))){
        perror("inet_ntop");
        exit(1);
    }
    printf("client(%s:%d)  is connected!",ipv4_addr,htons(cin.sin_port));
    pthread_create(&tid,NULL,(void *)cli_data_handle,(void *)&newfd);

}
#else
    struct sockaddr_in cin;
    socklen_t addrlen = sizeof(cin);
    while(1){
    if ((newfd = accept(fd,(struct sockaddr *)&cin,&addrlrn))<0){
        perror("accept");
        break;    
    }
    /*创建一个子进程用于处理已建立连接的客户的交流数据*/
    if((pid = fork()) < 0)
    {
        perror("fork");
        break;
    }
    if(0 == pid)//子进程
    {
        close(fd);
        char ipv4_addr[16];
        if(!inet_ntop (AF_INET,(void *)&cin.sin_addr,ipv4_addr,sizeof(cin)))
        {
            perror("inet_ntop");
            exit(1);
        }
        printf("client(%s:%d) is connected!\n",ipv4_addr,ntohs(cin.sin_port));
        cli_data_handle(&newfd);
        return 0;
    }else{
        //实际上此处pid>0,父进程中
        close(newfd);
    }





}

#endif
   close(fd);
   return 0;
}

void cli_data_handle(void * arg)
{
    int newfd = *(int *)arg;
    printf("handler thread: newfd = %d\n",newfd);
    int ret = -1;
    char buf[BUFSIZ];
    while(1){
        bzero(buf,BUFSIZ);
        do{
            ret = read(newfd,buf,BUFSIZ-1);
         }while(ret<0 &&EINTR == errno);
        if(ret < 0)
        {
            perror("read");
            exit(1);
        }
        if(!ret)  //对方已关闭
        {
            break;
        }
    }




}

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值