beginner
beginner

Reputation: 2032

Send and receive message on both ends

I have the following client and server code.

server.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/utsname.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<unistd.h>

#define MAX_DATA 1024
#define BUFFER 1024

int _GetHostName(char *buffer, int lenght);

const char MESSAGE[]="Hello, World!\n";
const int BACK_LOG=5;

int main(int argc, char *argv[]){
    int serverSocket=0, on=0, port=0, status=0, childPid=0;
    struct hostent *hostPtr=NULL;
    char hostname[80]="";
    char data[MAX_DATA];
    struct sockaddr_in serverName={0};

    char input[BUFFER];
    char output[BUFFER];
    int len;


    if(2!= argc){
        fprintf(stderr, "Usage : %s <port>\n", argv[0]);
        exit(1);
    }
    port=atoi(argv[1]);
    serverSocket=socket(PF_INET,SOCK_STREAM, IPPROTO_TCP);
    if(-1==serverSocket){
        perror("socket()");
        exit(1);
    }

    on=1;
    status=setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
    if(-1==status){
        perror("setsockopt(...,SO_REUSEADDRE,...)");
    }

    {
        struct linger linger={0};
        linger.l_onoff=1;
        linger.l_linger=30;
        status=setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, (const char*)&linger, sizeof(linger));
        if(-1==status){
            perror("setsockopt(...,SO_LINGER,...)");
        }
    }

    status=_GetHostName(hostname, sizeof(hostname));
    if(-1==status){
        perror("_GetHostName()");
        exit(1);
    }

    hostPtr=gethostbyname(hostname);
    if(NULL==hostPtr){
        perror("gethostbyname()");
        exit(1);
    }

    (void)memset(&serverName,0,sizeof(serverName));
    (void)memcpy(&serverName.sin_addr, hostPtr->h_addr,hostPtr->h_length);

    serverName.sin_family=AF_INET;
    serverName.sin_port=htons(port);

    status=bind(serverSocket, (struct sockaddr*)&serverName,sizeof(serverName));
    if(-1==status){
        perror("bind");
        exit(1);
    }


    status=listen(serverSocket, BACK_LOG);
    if(-1==status){
        perror("listen()");
        exit(1);
    }

    for(;;){
        struct sockaddr_in clientName={0};
        int slaveSocket, clientLength=sizeof(clientName);

        (void)memset(&clientName,0,sizeof(clientName));

        slaveSocket=accept(serverSocket,(struct sockaddr*)&clientName, & clientLength);
        if(-1==slaveSocket){
            perror("accept()");
            exit(1);
        }

        childPid=fork();

        switch(childPid){
            case -1:perror("fork()");
            exit(1);
            case 0: close(serverSocket);
            if(-1==getpeername(slaveSocket, (struct sockaddr*)&clientName, &clientLength)){
                perror("getpeername()");
            }else{
                printf("Connection request from %s \n", inet_ntoa(clientName.sin_addr));

                int data_len=1;

                while(data_len){
                    data_len=recv(slaveSocket,data, MAX_DATA,0);
                    if(data_len){
                        //send(slaveSocket,data,data_len,0);

                        data[data_len]='\0';
                        printf("CLIENT: %s", data);

                        printf("SERVER : ");
                        fgets(input,BUFFER, stdin);
                        send(slaveSocket, input, strlen(input),0);
                    }


                }

            }

            printf("Client disconnected\n");
            close(slaveSocket);
            exit(0);
            default:close(slaveSocket);
        }
    }
    return 0;
}

int _GetHostName(char *buffer,int length){
    struct utsname sysname={0};
    int status=0;

    status=uname(&sysname);
    if(-1!=status){
        strncpy(buffer,sysname.nodename,length);
    }
    return(status);
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>


#define BUFFER 1024

int main(int argc, char *argv[]){
    int clientSocket, remotePort, status=0;
    struct hostent *hostPtr=NULL;
    struct sockaddr_in serverName={0};
    char buffer[256]="";
    char *remoteHost=NULL;

    char input[BUFFER];
    char output[BUFFER];
    int len;


    if(3!=argc){
        fprintf(stderr, "Usage: %s <serverHost> <serverPort> \n",argv[0]);
        exit(1);
    }
    remoteHost=argv[1];
    remotePort=atoi(argv[2]);
    clientSocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(-1==clientSocket){
        perror("socket()");
        exit(1);
    }

    hostPtr=gethostbyname(remoteHost);
    if(NULL==hostPtr){
        hostPtr=gethostbyaddr(remoteHost,strlen(remoteHost), AF_INET);
        if(NULL==hostPtr){
            perror("Error resolving server address ");
            exit(1);
        }
    }
    serverName.sin_family=AF_INET;
    serverName.sin_port=htons(remotePort);
    (void)memcpy(&serverName.sin_addr,hostPtr->h_addr,hostPtr->h_length);

    status=connect(clientSocket,(struct sockaddr*)&serverName,sizeof(serverName));
    if(-1==status){
        perror("connect()");
        exit(1);
    }

    while(1){
        printf("CLIENT: ");
        fgets(input,BUFFER, stdin);
        send(clientSocket, input, strlen(input),0);

        len=recv(clientSocket, output,BUFFER, 0);
        output[len]='\0';
        printf("SERVER : %s\n",output);
    }
    close(clientSocket);


}

The server code above can receive and send message from and to the client. The client also can receive and send message from and to the server. However, they can only send one message at a time. Before the client can send more message, it needs to wait for the server first to send single message. The same with the server. How to make them receive and send multiple messages without waiting for the other end to reply?

enter image description here

Upvotes: 0

Views: 1816

Answers (2)

alk
alk

Reputation: 70931

Use select() on the socket and on stdin and perform a read/receive from whichever of the both becomes ready to read. If reading is done write/send either to stdout or to the socket.

In the server "socket" would refer to the accepted socket, in the client to the connected socket.


Unrelated, but still important:

This

char data[MAX_DATA];

...

data_len=recv(slaveSocket,data, MAX_DATA,0);
if(data_len){
  data[data_len]='\0';

...

could lead to buffer overflow the moment MAX_DATA bytes had been received, as then the 0 would be written 1 off the end of data.

To fix this define data like this:

char data[MAX_DATA + 1];

Also all code completely misses error checking for the calls to recv() and send(). This is bad.

Upvotes: 1

iceeggocean
iceeggocean

Reputation: 174

My understanding is that, you want to continue sending without waiting for the server's response.

A simple way to implement that is to use the poll() function to check first for any response. You will only call recv() when you're sure there is data to be read.

int pollForData(int sock) {
    struct pollfd pollSock;
    pollSock.fd = sock;
    pollSock.events = POLLIN;
    return  poll(&pollSock, 1, 10);
}

Upvotes: 1

Related Questions