c + + communication evolution level 1 -- single thread synchronous blocking communication

Keywords: socket Session Windows

This article records an example of using socket to communicate on windows. The code comes from the Internet. As time goes by for a long time, I didn't bookmark at that time, and now it's not easy to find a source. Some key code fragments are given in this paper. On the one hand, they are used to consolidate what I have learned, and on the other hand, they are used for vertical technical comparison and deeper understanding. The full address is here: address.  

First look at the project structure:

Key code of server:

int main(){
    //Load Winsock library and initialize socket resources
    initialization();
    //Create socket
    SOCKET s_server;
    s_server = socket(AF_INET,SOCK_STREAM,0);
    //Binding information
    bindInfo(&s_server);
    //Set socket to listen state
    changtoListen(&s_server);
    SOCKET commandSock;
    responseAccept(commandSock,&s_server);
    //Signal communication
    onInteract(&commandSock);
    //End
    onClose(&commandSock,&s_server);
    return 0;
}

Generally speaking, it goes through standard socket steps: generate local socket - > bind() - > listen() - > accept() - > communication transmission - > close;

In this process, the key point is accept(). In this code, it is blocked synchronously. The code is as follows:

//Response connection status
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 << "connection failed!Error code:"<<WSAGetLastError() <<std::endl;
        WSACleanup();
        return 0;
    }
    _sock = s_accept;
    std::cout << "Connection establishment,Prepare to receive data!" <<std::endl;
}

The result of the receive is a socket object; at the same time, the receive process is blocked. All communication with the client will be based on the currently received socket object.  

I abstract the communication between the server and the client into a method, which is called interactive onInteract(), and the code is as follows:

//Using the returned socket for communication
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 <<"Accept failure!Error code:"<<WSAGetLastError()<<std::endl;
            break;
        }else if(recv_len==0){
            std::cout <<"End of session!"<<std::endl;
        } else{
            std::cout <<"Client information:"<<recv_buf<<std::endl;
        }
        std::cout <<"Please enter reply information:";
        std::cin>> send_buf;
        send_len = send(*s_accept,send_buf,100,0);
        if(send_len<0){
            std::cout <<"fail in send!Error code:"<<WSAGetLastError() <<std::endl;
            break;
        }
    }
}

The key point of the local code is that: recv() and send() are both blocking ways. Its performance is: a send, a receive so cycle. In addition, the received information should also be discriminated to control the end of communication, thus forming the actual application layer protocol (but not added in this example, because at this time, I don't want to modify the code, so I really have no energy).  

Next, take a look at the client code:

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;
}

Its standard process is: generate local socket - > connect() - > process of message communication - > close.  

Note that: connect() is an immediate return method, and the connection is controlled by tcp/udp. After the communication process, I still abstract it into a method called onActive(). The code is as follows:

//Communicate with server
void onActive(SOCKET& s_server){
    char send_buf[100];
    char recv_buf[100];
    int recv_len;
    int send_len;
    while (1){
        std::cout<<"Please enter the sending information:";
        std::cin>>send_buf;
        send_len = send(s_server,send_buf,100,0);
        if (send_len<0){
            std::cout <<"fail in send!"<<std::endl;
            break;
        }
        recv_len = recv(s_server,recv_buf,100,0);
        if (recv_len<0){
            std::cout <<"Failure to receive!"<<std::endl;
            break;
        } else{
            std::cout <<"Server information:"<<recv_buf<<std::endl;
        }
    }
}

The key is still the send() method and the recv() method, which are also blocked.

The final effect is as follows:

Conclusion:

1. In the process of practice, the space character will be treated as a component segment operation, such as "ping hello", which will be understood as twice send. This shows that in the read-write byte stream of socket, most of the control characters may be escaped.

2. In the current way of implementation, read and write operations are running alternately. Moreover, read and write operations are blocked (sending and receiving is an alternative read and write operation).

3. In the current implementation, the server is single threaded, so don't confuse it. It receives socket instead of thread. This also means that only one session can be accessed at a time. (because the call is based on the received socket handle.). In addition, socket and thread are not necessarily related, they actually represent two kinds of resources.

334 original articles published, 157 praised, 120000 visitors+
Private letter follow

Posted by Daukan on Tue, 10 Mar 2020 04:33:44 -0700