Regarding a simple TCP based echo server using Soc

2019-07-09 09:08发布

问题:

I am learning the Sockets networking API. In this process, I have written a simple Echo server that uses TCP. I wrote the code in such a way that, as long as the server is running, anything typed on the client's console should be echoed back to it. However, I am unable to achieve this. Although, for the first input, I get the echo, from next time onwards, I do not get any message. I know, we can implement it to run for many clients using fork(), but I want to know the reason behind the blocking of the client, and if possible ways to correct it. Here is the code for the client:

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

#define MAXCOUNT 1024

int main(int argc, char* argv[])
{
    int sfd;
    char msg[MAXCOUNT];
    char blanmsg[MAXCOUNT];
    struct sockaddr_in saddr;

    memset(&saddr,0,sizeof(saddr)); 
    sfd = socket(AF_INET,SOCK_STREAM,0);
    saddr.sin_family = AF_INET;
    inet_pton(AF_INET,"127.0.0.1",&saddr.sin_addr);
    saddr.sin_port = htons(5004);

    connect(sfd,(struct sockaddr*) &saddr, sizeof(saddr));
    for(; ;) {
        memset(msg,0,MAXCOUNT);
        memset(blanmsg,0,MAXCOUNT);
        fgets(msg,MAXCOUNT,stdin);
        send(sfd,msg,strlen(msg),0);
        recv(sfd,blanmsg,sizeof(blanmsg),0);
        printf("%s",blanmsg);
        fflush(stdout);
    }
    exit(0);
}   

Here is the code for the server:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>

#define MAXCOUNT 1024

int main(int argc, char* argv[])
{
    int sfd,nsfd,n,i,cn;
    char buf[MAXCOUNT];
    socklen_t caddrlen;
    struct sockaddr_in caddr,saddr; //Structs for Client and server Address in the Internet 

    sfd = socket(AF_INET,SOCK_STREAM,0);
    memset(&saddr,0,sizeof(saddr)); //Clear the Server address structure

    saddr.sin_family = AF_INET; //Internet Address Family
    saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    saddr.sin_port = htons(5004);

    bind(sfd, (struct sockaddr*) &saddr,sizeof(saddr));
    listen(sfd,1);

    for(; ;) {
        caddrlen = sizeof(caddr);
        nsfd = accept(sfd,(struct sockaddr*) &caddr,&caddrlen);
        cn = recv(nsfd,buf,sizeof(buf),0);
        if(cn == 0) {
            exit(0);
        }
        buf[cn] = '\0';
        send(nsfd,buf,strlen(buf),0);
        }
    close(nsfd);
    exit(0);
}       

回答1:

You shouldn't call accept within the loop on the server. Move the accept before the for loop on the server and it should work how you expect.

Calling accept in the loop like that will make the server block until a new connection comes in. Your client is only opening a single connection, so the server will block on the second call to accept.



回答2:

Your code is doing precisely what you asked it to do. You told it to accept a connection, receive some data from that connection, send that data back to the connection, then accept another connection. That's what it's doing. I suspect you want to move the accept call outside the for loop.



回答3:

I think you required a code which servers multiple clients as well as echo message to respective clients.
so just have a look to your code again and note down modification

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MAXCOUNT 1024

int main(int argc, char* argv[])
{
int sfd,nsfd,n,i,cn;
char buf[MAXCOUNT];
socklen_t caddrlen;
struct sockaddr_in caddr,saddr; 
//Structs for Client and server Address in the Internet 

sfd = socket(AF_INET,SOCK_STREAM,0);
memset(&saddr,0,sizeof(saddr)); //Clear the Server address structure

saddr.sin_family = AF_INET; //Internet Address Family
saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
saddr.sin_port = htons(5004);

bind(sfd, (struct sockaddr*) &saddr,sizeof(saddr));
listen(sfd,5);/*request queue size*/
while(1)
{//main loop for cuncorent server
caddrlen = sizeof(caddr);
nsfd = accept(sfd,(struct sockaddr*) &caddr,&caddrlen);
if(fork()==0)
 {//only child code for serving a particular client
for(; ;) {//loop for reading and writing back msg cotineously


    cn = recv(nsfd,buf,sizeof(buf),0);
    if(cn == 0) {
        exit(0);
    }
    buf[cn] = '\0';
    send(nsfd,buf,strlen(buf),0);
    }//serving loop ends
close(nsfd);
exit(0);
   }//child code ends
  }//main while loop ends

exit(0);
}