1

我正在尝试编写一个执行以下操作的 TCP 客户端:

1. Establish TCP connection to webserver
2. Accept GET request command from user's console
3. Client should get a reply back from webserver after each GET request.

我在第三种情况下遇到了困难。我没有收到来自网络服务器的任何回复。

这是我的代码:

    s = connectTCP(host, service);
 while (fgets(buf, sizeof(buf), stdin)) {
   buf[LINELEN-2]='\r';    /* ensure catridge return   */
   buf[LINELEN-1]='\n'; /* ensure line feed return  */
   buf[LINELEN] = '\0'; /* ensure line null-terminated */
   outchars = strlen(buf);
   (void) write(s, buf, outchars);
   printf("Start reading from socket...\n");
   fflush(stdout);
   while( (n = read(s, buf, LINELEN)) > 0) {
    buf[n] = '\0';  /* ensure null-terminated */
    (void) fputs( buf, stdout );
    fflush(stdout);
   }
 }
4

3 回答 3

1

HTTP 请求以两个回车换行(“\r\n\r\n”)序列终止。您构建请求的方式甚至无法确保它有一个。也许改为:

while (fgets(buf, sizeof(buf) - 3, stdin)) {
    size_t outsz = strlen(buf);
    if (outsz > 0 && buf[outsz - 1] == '\n')
        outsz--;
    strcpy(buf + outsz, "\r\n\r\n");
    write(s, buf, outsz + 4);
于 2010-09-17T10:53:12.860 回答
0

你用的是什么插座?如果您使用(Windows)伯克利套接字,您可以使用它select来测试数据和recv/recvfrom获取数据

于 2010-09-17T10:46:16.787 回答
0

此代码中有几个可能导致问题的开放式漏洞。真的,我赌第2点。

1-connectTCP真的有效吗?它是否真的返回了一个工作的 TCP 套接字。您可以在调用时轻松关闭那个检查错误,write()而不是将它们强制转换为 void。

2-如果 LINELEN 是某个常数,例如数组的大小,\r\n如果用户输入和数组末尾之间存在垃圾(很可能有一些 0),则放在数组末尾不会有太大帮助。sizeof(buf)是最大的合法值,不一定是用户输入的大小。

3- double\r\n不是必需的,一个 '\n' (unix 约定)就足够了。

4 - 使用交互式用户输入进行测试通常不是一个好主意,它会使代码更难调试和测试。

5 -n如果读取缓冲区已满,请注意在缓冲区中的位置写入,它可能超过缓冲区末尾。

5 - 如果您想要的不仅仅是发送一个命令并获得答案,您将不得不编写更精细的代码来管理 write() 和 read()。正如另一位海报所建议的那样,选择可能是一个好主意(可能比线程简单)。您还可以阻止发送和接收命令之间的更多交替,但所有这些可能都是针对其他问题的。

下面是一段得到答案的工作代码(在 Linux 上使用 gcc 测试)。和你最初的没有什么不同,希望它能帮助你填补漏洞。

#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/un.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

enum {
    LINELEN = 1024
};

int main(){
    char buf[LINELEN];
    int n = 0;
    unsigned int option_len;
    int allow_reuse = 1;
    int sck = socket(PF_INET, SOCK_STREAM, 0);
    char * ip = "www.google.com";
    char * command = "GET http://www.google.com\n";

    /* connect to socket */
    struct sockaddr_in s;
    memset(&s, 0, sizeof(struct sockaddr_in));
    s.sin_family = AF_INET;
    s.sin_port = htons(80);
    s.sin_addr.s_addr = inet_addr(ip);
    if (s.sin_addr.s_addr == INADDR_NONE) {
        struct hostent *h = gethostbyname(ip);
        if (!h) {
            printf("DNS resolution failed for %s\n", ip);
            exit(0);
        }
        s.sin_addr.s_addr = *((int*)(*(h->h_addr_list)));
    }
    connect(sck, (struct sockaddr*)&s, sizeof(s));

    /* write command */
    printf("Write to socket...\n");
    write(sck, command, strlen(command));

    /* get answer */
    printf("Start reading from socket...\n");
    while((n = read(sck, buf, LINELEN-1)) > 0) {
       buf[n] = '\0';  /* ensure null-terminated */
       fputs( buf, stdout );
    }
}
于 2010-09-17T11:23:31.547 回答