zoukankan      html  css  js  c++  java
  • socket编程 ------ 建立 TCP 服务器和客户端流程(阻塞方式)

    服务器端:

    服务器端先创建一个socket,然后把这个socket绑定到端口上,接着让它向tcp/ip协议栈请求一个监听服务并创建一个accept队列来接受客户端请求。

    void creat_tcpServer()
    {
        int32    listenfd;
        
        /*    Create socket for incoming connections    */
        do{
            //AF_INET(又称 PF_INET)是 IPv4 网络协议的套接字类型
            //SOCK_STREAM 指TCP通信
         //0:系统根据地址格式和套接字类型,自动选择一个合适的协议,因为这里是TCP,也可填IPPROTO_TCP
            listenfd = socket(AF_INET, SOCK_STREAM, 0);
            if(listenfd    ==    -1)    
            {
                vTaskDelay(1000/portTICK_RATE_MS);
            }
        }while(listenfd    ==    -1);
        
        
        
        struct    sockaddr_in    server_addr;
        int32    ret;
        /*    Construct local address structure    */
        memset(&server_addr, 0, sizeof(server_addr));/*    Zero out structure */
        server_addr.sin_family    = AF_INET;    /*    Internet address family    */
        server_addr.sin_addr.s_addr    = INADDR_ANY;
        server_addr.sin_len    = sizeof(server_addr);
        server_addr.sin_port = htons(9999);    /* Local port */
        //绑定socket:将创建的socket绑定到本地的IP地址和端口,此socket是半相关的,只是负责
        //侦听客户端的连接请求,并不能用于和客户端通信
        do{
            ret    = bind(listenfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
            if    (ret !=    0)    
            {
                vTaskDelay(1000/portTICK_RATE_MS);
            }
        }while(ret != 0);
    
        
        
        //listen侦听: 第一个参数是套接字,第二个参数为accept队列大小,当服务器接收到第三次握手后
        //将连接放到这个队列中,直到被accept处理才清除。当accept队列满了之后,即使client继续向server发
        //送ACK的包,也会不被响应,此时ListenOverflows+1,同时server通
        //过/proc/sys/net/ipv4/tcp_abort_on_overflow(linux kernel 2.2之后)来
        //决定如何返回,0表示直接丢弃该ACK,1表示发送RST通知client;相
        //应的,client则会分别返回read timeout 或者 connection reset by peer。
        do{
        /*    Listen    to    the    local    connection    */
            ret    = listen(listenfd, 1);
            if(ret != 0)
            {
                vTaskDelay(1000/portTICK_RATE_MS);
            }
        }while(ret    !=    0);
    
        
        
        int32 client_socket;
        int32 len = sizeof(struct sockaddr_in);
        int32 recbytes;
        struct    sockaddr_in    remote_addr;
        
        for(;;)
        {
            /*block    here waiting remote connect request*/
            if((client_socket = accept(listenfd, (struct sockaddr *)&remote_addr,    (socklen_t *)&len))    < 0)    
            {
                continue;
            }
    
            char *recv_buf = (char *)zalloc(129);
    
            while ((recbytes = read(client_socket , recv_buf, 128)) > 0)    
            {
                //数据保存在recv_buf
            }
            free(recv_buf);
    
            if(recbytes <= 0)
            {
                close(client_socket);
            }
        }
    }

     客户端:

        for(;;)
        {
            
            sta_socket = socket(PF_INET, SOCK_STREAM, 0);
            if (-1 == sta_socket)
            {
                close(sta_socket);
                vTaskDelay(1000/portTICK_RATE_MS);
                printf("ESP8266 TCP client task > socket fail!
    ");
                continue;
            }
            printf("ESP8266 TCP client task > socket ok!
    ");
            
         //开启keepalive
         keepalive = 1;
    if(setsockopt(sta_socket, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(keepalive)) < 0) { printf("set keepalive fail"); } bzero(&remote_ip, sizeof(struct sockaddr_in)); remote_ip.sin_family = AF_INET; remote_ip.sin_addr.s_addr = inet_addr(server_ip); remote_ip.sin_port = htons(server_port); if(0 != (connect_status = connect(sta_socket, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)))) { close(sta_socket); vTaskDelay(1000/portTICK_RATE_MS); printf("ESP8266 TCP client task > connect fail! "); continue; } printf("ESP8266 TCP client task > connect ok! ");
         //如该连接在60秒没有任何数据往来,则进行探测 keepidle = 60 setsockopt(sta_socket, IPPROTO_TCP, TCP_KEEPIDLE, (
    void*)&keepidle , sizeof(keepidle));
         //探测时发包的时间间隔为5秒
         keepinterval = 5; setsockopt(sta_socket, IPPROTO_TCP, TCP_KEEPINTVL, (
    void *)&keepinterval , sizeof(keepinterval));
         //探测尝试的次数,如果第1次探测包就收到响应,则后2次的不再发
    keepcount = 3; setsockopt(sta_socket, IPPROTO_TCP, TCP_KEEPCNT, (
    void *)&keepcount , sizeof(keepcount));     setsockopt(sta_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flag , sizeof(flag)); while ((recbytes = read(sta_socket , recv_buf, 32)) > 0) {
    handle_server_data(recv_buf, recbytes); } if(recbytes <= 0) { close(sta_socket); printf("ESP8266 TCP client task > server closed! "); } }
  • 相关阅读:
    WebGL-四之二
    WebGL-四之一
    mybatis中批量更新的问题
    nginx+tpmcat+redis实现session共享
    myeclipse快捷方式汇总
    StringBuffer的append方法比“+”高效
    《Thinking in Java》 And 《Effective Java》啃起来
    JAVA链表中迭代器的实现
    myeclipse从SVN检出项目报错
    C#中清空ListView中的数据
  • 原文地址:https://www.cnblogs.com/god-of-death/p/7131567.html
Copyright © 2011-2022 走看看