c++ 通信演进level1 ----单线程同步阻塞通信

  本篇,纪录一个在 windows上使用 socket进行通信的例子,代码源自于网上。由于时间过去挺久了,当时我也没有加书签,现在暂时还不好找出处。 文中给出一些关键代码片段,一方面用于巩固我所学的知识,另一方面,用于纵向的技术对比,加深理解。完整的地址在这里:地址。 

  首先看看项目结构:

 服务端的关键代码:

int main(){
    //加载Winsock库,初始化socket资源
    initialization();
    //创建套接字
    SOCKET s_server;
    s_server = socket(AF_INET,SOCK_STREAM,0);
    //绑定信息
    bindInfo(&s_server);
    //将socket设置为lisen状态
    changtoListen(&s_server);
    SOCKET commandSock;
    responseAccept(commandSock,&s_server);
    //通信
    onInteract(&commandSock);
    //结束
    onClose(&commandSock,&s_server);
    return 0;
}

  总体而言,就是经过标准的socket步骤: 生成本地socket->bind()  -> listen() -> accept() -> 通信传输 -> 关闭;

  这个过程中,关键点在于accept(),在本次代码中,它是同步阻塞的,代码如下:

//响应连接状态
int responseAccept(SOCKET& _sock,SOCKET* _s_server){
    int len = sizeof(SOCKADDR);
    SOCKADDR_IN accept_addr;
    SOCKET s_accept= accept(*_s_server,  (SOCKADDR *)&accept_addr, &len);
    if (s_accept==SOCKET_ERROR){
        std::cout << "连接失败!错误码:"<<WSAGetLastError() <<std::endl;
        WSACleanup();
        return 0;
    }
    _sock = s_accept;
    std::cout << "连接建立,准备接受数据!" <<std::endl;
}

   接收的结果是 套接字对象;同时,这个接收的过程是 阻塞的。   与客户端的所有通信将基于当前接收的套接字对象进行。 

   我将 服务器与客户端的通信 抽象为一个方法,称之为  互动 onInteract(),代码如下:

//利用返回的套接字进行通信
void onInteract(SOCKET* s_accept){
    int recv_len =-1;
    int send_len = -1;
    char recv_buf[100];
    char send_buf[100];
    while (1){
        recv_len = recv(*s_accept,recv_buf,100,0);
        if (recv_len<0){
            std::cout <<"接受失败!错误码:"<<WSAGetLastError()<<std::endl;
            break;
        }else if(recv_len==0){
            std::cout <<"会话结束!"<<std::endl;
        } else{
            std::cout <<"客户端信息:"<<recv_buf<<std::endl;
        }
        std::cout <<"请输入回复信息:";
        std::cin>> send_buf;
        send_len = send(*s_accept,send_buf,100,0);
        if(send_len<0){
            std::cout <<"发送失败!错误码:"<<WSAGetLastError() <<std::endl;
            break;
        }
    }
}

  本地代码的关键点在于: recv(),与  send()  都是阻塞的方式。 它的表现是: 一次发送,一次接收 如此循环往复。  此外,还应对接收到的信息进行判别,用于控制通信的结束,也就形成了实际上的 应用层协议(但是在本例子中还未加,由于此时不想修改代码,确实没有精力)。 

    接着,再看一看客户端的代码:

int main(){
    initialization();
    SOCKET s_server;
    s_server = socket(AF_INET,SOCK_STREAM,0);
     onConnect(s_server);
    onActive(s_server);
    onClose(s_server);
    return 0;
}

    它的标准流程则是:  生成本地socket -> connect() -> 消息通信的过程 -> 关闭。 

    这其中的注意的是: connect()该方法是立即返回的,连接由tcp/udp进行控制。  之后通信的过程,我依然是抽象成的一个方法叫做: onActive(),代码如下:

//与服务器进行通信
void onActive(SOCKET& s_server){
    char send_buf[100];
    char recv_buf[100];
    int recv_len;
    int send_len;
    while (1){
        std::cout<<"请输入发送信息:";
        std::cin>>send_buf;
        send_len = send(s_server,send_buf,100,0);
        if (send_len<0){
            std::cout <<"发送失败!"<<std::endl;
            break;
        }
        recv_len = recv(s_server,recv_buf,100,0);
        if (recv_len<0){
            std::cout <<"接收失败!"<<std::endl;
            break;
        } else{
            std::cout <<"服务端信息:"<<recv_buf<<std::endl;
        }
    }
}

  其中的关键仍然是send()方法,recv()方法,它们当然也是阻塞的

  最终的效果如下: 

总结: 

    1.在实践过程中,空格字符会被 处理成 分段操作,譬如 "ping hello",  会理解为两次 send。这说明了在socket的读写字节流中,控制字符有可能大部分要经过转义

    2.当前方式实现中,读写操作是交替运行的。并且,读写操作是阻塞的(发送和接收是一种另类的读写操作)

    3.当前实现中,服务器是单线程的,不要搞混淆了,接收到的是 socket,而不是thread。  这也意味着,一次只能接入一个会话(或者接收到的多个会话进行线性处理。)。(因为通话的过程是基于接收到的socket句柄而进行的.) 。 此外,socket与线程并没有必然联系,它们实际上代表了两种资源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章