• Linux TCP server 只能接受一个 TCP 连接


    #include <stdio.h>
    
    #include <sys/types.h> 
    #include <sys/socket.h> 
    
    #include <string.h> // menset 函数
    #include <stdlib.h> // exit 函数
    
    #include<netinet/in.h> // struct sockaddr_in 结构类型
    
    #include<arpa/inet.h> // inet_ntoa 函数
    
    #include <unistd.h> // close 函数
    
    int tcpServerInit( void );
    
    void main()
    {
        //2017年11月28日11:18:18,suozhang,add
        printf("2017年11月28日11:18:39,hello,world!
    ");
        
        tcpServerInit();
    
    }
    
    
    int tcpServerInit( void )
    {
          // AF_INET     : IPV4网络协议 
          // SOCK_STREAM : 提供双向连续且可信赖的数据流,即TCP,支持OOB机制,在所有数据传输前必须使用connect()来建立连接状态
          // 0           : 用来指定socket所使用的传输协议编号,通常此参考不用管他,设为0即可
          int tcpServerSocket = socket(AF_INET, SOCK_STREAM, 0);
          
          if(tcpServerSocket < 0)  
          {  
              // 创建 socket 失败
              // perror(s) 用来将上一个函数发生错误的原因输出到标准设备(stderr)。
              perror("new tcpServerSocket error is ");
              
              //exit(-1)表示程序异常退出
              exit(-1);
          }
          
          //定义 服务器 IP地址和端口号 结构体变量
          struct sockaddr_in tcpServerAddr;
          
          //将结构体清空
          memset(&tcpServerAddr,0,sizeof(tcpServerAddr));
          
          tcpServerAddr.sin_family = AF_INET;  // AF_INET : IPV4网络协议 
          
          // htons() 函数用来将 16位 类型 转换为 网络字符顺序
          tcpServerAddr.sin_port = htons(9527);// 绑定端口号为9527,通常是大于1024的一个值
          
          // inet_addr() 函数用来将IP地址字符串转换成网络所使用的二进制数字
          tcpServerAddr.sin_addr.s_addr = inet_addr("10.1.51.53");// 这里可填写 INADDRY_ANY 表示服务器自动填充本机IP地址
          
          if( bind(tcpServerSocket, (struct sockaddr*)&tcpServerAddr, sizeof(tcpServerAddr)) < 0 )   
          {               
               //绑定失败
               perror("bind tcpServerSocket err is ");
               
               close( tcpServerSocket ); //绑定失败,因此关闭创建的 socket
               
               //exit(-1)表示程序异常退出
               exit(-1);
          }   
          
          
                  printf("TCP server ip: %s  and port: %d.
    ", inet_ntoa(tcpServerAddr.sin_addr), ntohs(tcpServerAddr.sin_port));  
                  
                  
      
          //监听socket ,第二个参数规定了内核应该为相应套接口排队的最大连接个数。  
          if( listen(tcpServerSocket, 5) < 0)  
          {  
               //监听失败  
               perror("listen tcpServerSocket err is ");
               
               close( tcpServerSocket ); //绑定失败,因此关闭创建的 socket
               
               //exit(-1)表示程序异常退出
               exit(-1);
          }
          
    
          
            
          struct sockaddr_in tcpClientAddr;
          
          //将结构体清空
          memset(&tcpClientAddr,0,sizeof(tcpClientAddr));
          
          socklen_t tcpClientAddrLen = sizeof(struct sockaddr);
          
          // accept() 函数 接受远程计算机的连接请求,建立与客户机之间的通信连接。
          // 服务器处于监听状态时,如果某时刻获得客户机的连接请求,此时并不是立即处理这个请求,
          // 而是将这个请求放在等待队列中,当系统空闲时再处理客户机的连接请求。
          // 重点: 当 accept() 函数接受一个连接时,会返回一个新的socket标识符,
          // 以后的数据传输和读取就要通过这个新的socket编号来处理,
          // 原来参数的socket(这里指 tcpServerSocket )也可以继续使用,继续监听其他客户机的连接请求
          // 因此 服务器跟一个客户端连接成功,就会产生两个套接字,一个当初自己创建的,一个 accept() 创建的
          
          int tcpClientSocket = accept(tcpServerSocket, (struct sockaddr*)&tcpClientAddr, &tcpClientAddrLen);
    
          if( tcpClientSocket < 0 )  
          {  
               perror("accept tcpServerSocket err is ");  
              
               close( tcpServerSocket ); //绑定失败,因此关闭创建的 socket
               
               //exit(-1)表示程序异常退出
               exit(-1);
          }  
          else  
          {  
              printf("connected with ip: %s  and port: %d.
    ", inet_ntoa(tcpClientAddr.sin_addr), ntohs(tcpClientAddr.sin_port));  
          } 
          
          char buf[1024] ={ 0 };
          
          for( ;; )
          {
              if( recv( tcpClientSocket, buf, sizeof( buf ),0 ) < 0 )
              {
                   perror("recv tcpClientSocket err is ");  
                  
                   close( tcpServerSocket ); //绑定失败,因此关闭创建的 socket
                   
                   close( tcpClientSocket ); //绑定失败,因此关闭创建的 socket
                   
                   //exit(-1)表示程序异常退出
                   exit(-1);
              }
              
              printf("接收的数据是:%s.
    ",buf);
              
              //将接收的数据发回客户端
              if( send( tcpClientSocket,buf,strlen(buf),0 ) < 0 )
              {
                   perror("send tcpClientSocket err is ");  
                  
                   close( tcpServerSocket ); //绑定失败,因此关闭创建的 socket
                   
                   close( tcpClientSocket ); //绑定失败,因此关闭创建的 socket
                   
                   //exit(-1)表示程序异常退出
                   exit(-1);
              }
              
              //将接收缓冲区清空
              memset(buf,0,sizeof(buf));
              
          }
        
    }
  • 相关阅读:
    Django Rest Framework(认证、权限、限制访问频率)
    MySql 三大知识点——索引、锁、事务
    django聚合查询
    Python装饰器用法
    linux上ssh免密登录原理及实现
    为github公开项目单独设置用户名
    golang协程池设计
    Django-Signals信号量
    linux tcp相关参数
    记一次性能优化,限制tcp_timewait数量,快速回收和重用
  • 原文地址:https://www.cnblogs.com/suozhang/p/8081057.html
Copyright © 2020-2023  润新知