echo服务器示例

时间:2012-07-06 07:22:42

标签: c++ sockets network-programming

我编写了以下代码以便创建一个echo服务器(我写入stdout的数据从我的PC移动到服务器并返回到我的PC)。问题是回声没有显示在客户端的终端上。有2个server.cpp进程正在运行,所以我知道我的连接已被服务器接受。完整代码为here,以便您可以直接复制和运行代码。代码的相关部分是:

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

4 个答案:

答案 0 :(得分:3)

在server.c中,替换错误的行:

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

用这个正确的:

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

<小时/> 除了:您使用的是什么编译器?当看到该行时,g ++打印出警告:

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

在使用g ++或gcc编译时,我尝试始终使用-Wall -Werror

答案 1 :(得分:1)

您使用无效参数调用server.cpp中的accept。第三个参数必须包含第二个参数指向的结构的大小:

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

答案 2 :(得分:1)

您确定,您是通过stdin在客户端输入100个字符吗?

如果没有,您向服务器写入的字符少于100个,但服务器需要100个字符,因此服务器端read()会阻塞。

您可以通过修改客户端代码来解决此问题:

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

另一种方法是将客户端 - >服务器通信分成两部分:

1发送要回显的数据大小

2自行发送数据

通过这样做,您可以让服务器调整要读取的字符数,然后回显。


只要不将write()返回的值检查为-1,下面的结构就没有意义。

write()的调用将阻塞,直到写入n个字节,或者在出错时返回-1。后者会制造你的逻辑。

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

你可能想尝试这样的事情:

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

此问题适用于服务器以及客户端。

答案 3 :(得分:0)

一些缩进会很好,但我也建议你重新编写它,检查不同的函数,如“mathematician1975”。 你可以在谷歌上找到很多例子。还有man accept中的一个。 我建议您查看:pollselect以避免fork