如何修复server.c和client.c中的while循环

时间:2017-03-08 21:55:42

标签: c

server.c

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

void error(char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
     int sockfd, newsockfd, portno, clilen;
     char buffer[256];
     struct sockaddr_in serv_addr, cli_addr;
     int n;
     char *result1 = "Ian G. Harris";
     char *result2 = "Joe Smith";
     char *result3 = "Jane Smith";
     if (argc < 2) 
     {
         fprintf(stderr,"ERROR, no port provided\n");
         exit(1);
     }
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
     {
        error("ERROR opening socket");
     }
     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = atoi(argv[1]);
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0) 
              error("ERROR on binding");
     listen(sockfd,5);
     clilen = sizeof(cli_addr);
     newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
     if (newsockfd < 0) 
     {
          error("ERROR on accept");
     }
     while (strcmp(buffer, "+++") != 0)
     {
         bzero(buffer,256);
         n = read(newsockfd,buffer,255);
         if (n < 0) error("ERROR reading from socket");
         printf("Address server started\n");
         if (strcmp(buffer, "harris@ics.uci.edu\n") == 0)
         {
             printf("%s\n", result1);
         }
         else if(strcmp(buffer, "joe@cnn.com\n") == 0)
         {
              printf("%s\n", result2);
         }
         else if(strcmp(buffer, "jane@slashdot.org\n")==0)
         {
             printf("%s\n", result3);
         }
     }
     return 0; 
}

client.c

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

void error(char *msg)
{
    perror(msg);
    exit(0);
}
int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[256];
    if (argc < 3) 
    {
           fprintf(stderr,"usage %s hostname port\n", argv[0]);
           exit(0);
    }
    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);
    if (server == NULL)
    {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR connecting");
    while (strcmp(buffer, "+++") != 0)
    {
        printf("> ");
        bzero(buffer,256);
        fgets(buffer,255,stdin);
        n = write(sockfd,buffer,strlen(buffer));
        if (n < 0) 
             error("ERROR writing to socket");
        bzero(buffer,256);
        n = read(sockfd,buffer,255);
        if (n < 0) 
             error("ERROR reading from socket");
        printf("%s\n",buffer);
    }
    return 0;
}

我是c的新手,我正在编写server.c和client.c。我的代码问题是我不能让程序继续输入,直到我输入“+++”退出。正确的输出如下所示:

客户终端:

> harris@ics.uci.edu
Ian G. Harris
> joe@cnn.com
Joe
>

服务器终端:

Address server started
harris@ics.uci.edu
joe@cnn.com

在我的代码中,当我在客户终端输入“harris@ics.uci.edu”时,它会执行以下操作:

> harris@ics.uci.edu
(empty line) 

并且它不再需要任何输入。

while循环中有什么问题吗?有人可以帮我解决吗?提前致谢。

2 个答案:

答案 0 :(得分:1)

少数事情:

在客户端循环中,您在套接字上执行writeread。但是您的服务器永远不会写入该套接字(服务器中没有write调用,只有read)。结果,您的客户在read电话上被屏蔽了。这就是为什么你不能输入更多...

通常,您需要检查您写入了多少并继续写入,直到完成(需要循环)。

int n = 0;
while (n != strlen(buffer){
   n += write(sockfd,&buffer[n],strlen(buffer)-n);      
}

从套接字读取也是如此:

int n = 0;
while (n != strlen(buffer){
   n += read(sockfd,&buffer[n],strlen(buffer)-n);      
}

答案 1 :(得分:0)

这是我认为可能发生的事情。

  1. 客户端发送一些数据。可能是所有字符串harris@ics.uci.edu,但可能更少。
  2. 服务器读取一部分内容,很可能少于完整字符串,比如说harris@ic
  3. 服务器执行strcmp,它与任何内容都不匹配,因此返回到循环的顶部。
  4. 服务器会读取电子邮件的剩余部分,将s.uci.edu 说成buffer,从而覆盖
  5. 同样,这与任何事情都不匹配,因此服务器再次转到while循环的顶部。
  6. 服务器挂起read电话,等待来自客户端的数据。由于客户端正在等待回复,因此它会停留在自己的read电话上。 ......没有别的事情发生。
  7. 这里有两个主要问题。首先,TCP套接字只是字节流,当您从它们读取数据时,操作系统不再保留它。如果需要,您现在可以处理任何先前或部分读取的数据。其次,操作系统经常发送(发送和接收)比您请求的字节更少的字节。当您要求发送完整字符串harris@ics.uci.edu时,只能发送一部分字符串,或者只能在另一侧读取其中的一部分。

    这对你来说意味着两件事。每次拨打read(2)write(2)时都要检查读取/写入的数据量,这一点非常重要,但在网络中它是至关重要的。确保您根据需要进行读/写(本例​​中为完整的电子邮件),然后再继续等待回复。

    第二件事是您需要某种方式来描述完整的消息并缓冲部分消息。在您所拥有的内容中,正如许多基于文本的消息传递协议所常见的那样,换行符\n是您的分隔符。因此,不需要在服务器中单次调用read(2),而是需要这样的东西(pseduocode):

    while newline not in data:
        data += read(sockfd, ...)
    

    收到换行符后,请处理完整的消​​息,但不要丢弃从下一条消息中读取的任何额外字节。保留它们,并将从套接字读取的下一个字节附加到它们,依此类推。

    编辑:

    请注意,使用套接字时,通常最好使用recv(2)send(2)read(2) / write(2)系统调用可以正常工作,但其他人在使用套接字时更清楚,并允许您指定其他标志,例如,查看套接字上当前的字节或在返回之前等待你请求的所有字节都可用。