AvinashK
AvinashK

Reputation: 3423

echo server example

I wrote the following code in order to make an echo server (data I write to stdout moves from my PC to server and back to my PC). The problem is that echo is not getting displayed on client's terminal. There are 2 server.cpp processes running so I know that my connection has been accepted by the server. Tthe full code is here so that you can directly copy and run the code. The relevant parts of code are:

server.cpp

void reflect(int x)
{
    int n;
    int m;
    char data[100];
    cout<<"Entered reflect function"<<endl; //this gets displayed

    n=read(x,data, 100); //***execution is not going beyond this point i.e. read is blocking***
    cout<<"Client sent "<<n<<endl; //this doesn't get displayed 

    if(n>0)
    {
        while(n>0)
        {
            m=write(x,data,n);
            n=n-m;
        }
    cout<<"Successfully echoed back to client"<<endl; //this doesn't get displayed 
    }
}

int main()
{
    sockaddr_in serv;
    bzero(&serv, sizeof(serv));
    serv.sin_family=AF_INET;
    serv.sin_port=htons(3345);
    inet_aton("127.0.0.1", &(serv.sin_addr));

    int servfd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    int x;
    x=bind(servfd, (sockaddr*)(&serv), sizeof(serv));

    cout<<"Bind returned"<<x<<endl; //this displays x as 0

    listen(servfd, 5);
    sockaddr cli;
    int connfd;
    pid_t id=-1;
    socklen_t siz=sizeof(cli);
    for(;;)
    {
        if(connfd=accept(servfd, &cli, &siz)>=0)
             id=fork();

        if(id==0)
             reflect(connfd);

        else 
             continue;
    }
}

client.cpp

int main()
{
    int clifd;
    clifd=socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
    sockaddr_in serv;
    bzero(&serv, sizeof(serv));
    serv.sin_family=AF_INET;
    serv.sin_port=htons(3345);
    inet_aton("127.0.0.1", &(serv.sin_addr));

    connect(clifd, (sockaddr*)(&serv), sizeof(serv));//blocking call
    int n,m;
    char data[100];
    char recvd[100];
    for(;;)
    {
        fgets(data, 100,stdin );
        n=strlen(data);
        cout<<"You have written "<<n<<endl; //this returns the correct value

        if(n>0)
        {
            while(n>0)
            {  
                 m=write(clifd,data,n);
                 n=n-m;
            }
        }

        n=read(clifd, recvd, 100);
        cout<<"Server echoed back "<<n<<endl; //this doesn't get displayed

        if(n>0)
        {
            while(n>0)
            {
                m=fputs(data,stdout);
                fflush(stdout);
                n=n-m;
            }
            //cout<<data<<endl;
        }
    }
}

Upvotes: 1

Views: 5398

Answers (4)

alk
alk

Reputation: 70971

Are you sure, you are inputting 100 characters on the client side via stdin?

If not, you are writing less then 100 characters to the server, but the server expects 100 characters, so the server side read() blocks.

You might solve this by modifying the client code like so:

while (n > 0)
{  
  m = write(clifd, data, sizeof(data));
  ...

A different approach whould be to split the client->server communication into two part:

1 Send the size of data to be echoed

2 Send the data itself

By doing so you allow the server to adjust the number of characters to read and then echo back.


This construct below does not make sense as long you do not check the value returned by write() to be -1.

The call to write() will block until n bytes are written or will return -1 on error. The latter will brake your logic.

while (n > 0)
{
  m=write(fd, data, n);
  n = n - m;
}

You might like to try something like this:

while (n > 0)
{
  m = write(fd, data, n);
  if (0 < m)
    n = n - m;
  else if (errno)
    perror("write()");
}

This issue applies to the server as also to the client.

Upvotes: 1

rgerganov
rgerganov

Reputation: 2232

You are calling accept in server.cpp with invalid arguments. The third argument must contain the size of the structure pointed by the second argument:

socklen_t siz = sizeof(cli);
for(;;)
{
    if((connfd=accept(servfd, &cli, &siz))>=0)
    ...

Upvotes: 1

Robᵩ
Robᵩ

Reputation: 168716

In server.c, replace this incorrect line:

if( connfd=accept(servfd, &cli, &siz) >=0 )

with this correct one:

if( (connfd=accept(servfd, &cli, &siz)) >=0 )


Aside: What compiler are you using? g++ printed a warning when it saw that line:

serv.cc: In function ‘int main()’:
serv.cc:45:43: warning: suggest parentheses around assignment used as truth value [-Wparentheses]

I try to always use -Wall -Werror when compiling with g++ or gcc.

Upvotes: 3

Damien Locque
Damien Locque

Reputation: 1809

Some indentation would be nice but i also recommend you to re-write it with a check on differents function like said "mathematician1975". You can fin lots of example on google. and also one in man accept. I recommand you to take a look at : poll or select to avoid the fork

Upvotes: 0

Related Questions