Home > Back-end >  sending two consecutive message via socket
sending two consecutive message via socket

Time:01-30

I have two codes one for server, written in C , and the other one for client, written in python. I am trying to create a chat bot but I bumpped into a problem when I tried to send to messages consecutively from the server to the client.

Here are my codes:

import socket

IP = "127.0.0.1"
PORT = 4456
ADDR = (IP,PORT)
SIZE = 1024
FORMAT = "utf-8"
    
if __name__ == "__main__":
    print("This is client!!!!!")
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(ADDR)
    data = client.recv(SIZE).decode(FORMAT)
    print(f"CONNECTED TO THE SERVER WITH MESSAGE {data}")
    print(data[-1])
    while(True):
        data = client.recv(SIZE).decode(FORMAT)
        print(f"[SERVER] {data}")
        if(data[-1] == "r"): break
        meg = input('press Y/N: ')
        client.send(meg.encode(FORMAT))
        
    while(True):
        meg = input('To sever:')
        client.send(meg.encode(FORMAT))
        data = client.recv(SIZE).decode(FORMAT)
        print(f"[SERVER] {data}")
        if(meg == "Done"): 
            client.close()
            break
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <iostream>

#define PORT 4456
using namespace std;

int main(){
    
    //Variables and structures
    int server_fd, client_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t addr_size;
    char buffer[1024];
    string inp; 

    // Server socket
    server_fd = socket(AF_INET, SOCK_STREAM, 0); //create the server socket

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    listen(server_fd, 5);
    printf("[LISTENING] Port number: %d\n", PORT);
    
    client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_size);
    printf("[CONNECTED] New Connection\n");
    strcpy(buffer, "Hello, this is a test message...");
    send(client_fd, buffer, strlen(buffer), 0);
    
    while(1){
        memset(buffer, '\0', sizeof(buffer));
        strcpy(buffer, "Please press Y/N");
        send(client_fd, buffer, strlen(buffer), 0);
        memset(buffer, '\0', sizeof(buffer));
        recv(client_fd, buffer, 1024, 0);
        if(strcmp(buffer,"Y") == 0){
            memset(buffer, '\0', sizeof(buffer));
            strcpy(buffer, "Readyrrrrr");
            send(client_fd, buffer, strlen(buffer), 0);
            break;
        }
    }
    while(1){
        
        memset(buffer, '\0', sizeof(buffer));
        recv(client_fd, buffer, 1024, 0);
        printf("[CLIENT]: %s\n", buffer);
        
        if(strcmp(buffer,"Done") == 0){
            inp = "Done signal received";
            strcpy(buffer, inp.c_str());
            send(client_fd, buffer, strlen(buffer), 0);
            close(client_fd);
            printf("[DISCONNECTED] Process Done \n");
            break;
        }
        
        cout<< "To client: ";
        getline(cin, inp);
        cout<<inp<<endl;
        
        strcpy(buffer, inp.c_str());
        send(client_fd, buffer, strlen(buffer), 0);
        
        printf("[CONTINUE].....\n");
    }
    return 0;
}

When you run both in separate windows, the output of the python is:

CONNECTED TO THE SERVER WITH MESSAGE Hello, this is a test message...Please press Y/N
N

But I expected:

CONNECTED TO THE SERVER WITH MESSAGE Hello, this is a test message...
.
[SERVER] Please press Y/N
Please press Y/N:

What should I do?

CodePudding user response:

send(client_fd, buffer, strlen(buffer), 0);

If you go back to your reference documentation and reread its description of send() you will find that it explains what send()'s return value means: the actual number of bytes written to a socket. Which is not guaranteed to be the same number of bytes as was passed into the third parameter. They can always be less if, for any number of reasons, your operating system is unable to immediately send the requested number of bytes. If, for example, this message was 30 bytes send() might return 20, indicating that only the first 20 bytes were sent, and the ten remaining bytes are unsent.

You must include the appropriate logic in your program to handle this situation.

recv(client_fd, buffer, 1024, 0);

Similarly, you have no guarantees, whatsoever, that the same number of bytes that were sent, will be recv() here as well. If those 30 bytes were sent, the other socket endpoint's recv() call might return 20, returning the first 20 bytes, and the next call to recv() will return the next 10 bytes.

You will need to fundamentally change the logic in your code to correctly handle socket protocol semantics. You cannot rely on specific number of bytes being sent and received, or that the same exact number of bytes that was sent gets received, in a matching sequence.

You will need to implement the appropriate logic, in your sent and received socket data, so that each socket endpoint can intelligently interpret the data that it receives, and can't make any assumptions that a recv() will just hand you, on a silver platter, what the other socket endpoint send()ed. Using sockets correctly is not that simple, and a good C textbook on network programming will introduce, and explain, many common, simple technique for properly implementing socket semantics.

CodePudding user response:

workaround

Add usleep(10); at the begining of the first while-loop in C source file, which may guarantee content in two send won't be combined together.

solve it completely

Use a message seperator as methioned by @Alan Birtle

  • Related