我正在尝试编写一个执行以下操作的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);
}
}
答案 0 :(得分:1)
HTTP请求以 two carriage-return-linefeed(“\ r \ n \ n \ n \ n \ 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);
答案 1 :(得分:0)
您使用的是哪些套接字?如果您使用(windows)berkley套接字,则可以使用select
来测试数据,使用recv
/ recvfrom
来获取数据
答案 2 :(得分:0)
此代码中有几个开环孔可能导致问题。我真的打赌第2点。
1- connectTCP真的有效吗?它确实返回了一个工作的TCP套接字。在调用write()
而不是将它们转换为void时,您可以轻松关闭那个检查错误。
2-如果LINELEN是一个类似于数组大小的常量,如果用户输入和数组末尾之间存在垃圾,那么将\r\n
放在数组的末尾将没有多大帮助(机会)可能有一些0)。 sizeof(buf)
是最大合法值,不一定是用户输入内容的大小。
不需要3-双\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 );
}
}