В этом коде есть несколько открытых отверстий, которые могут привести к этой проблеме. На самом деле я сделал ставку на 2-й раз.
1- действительно соединениеTCP действительно работает? Действительно ли он вернул рабочий TCP-сокет. Вы можете легко закрыть ту, которая проверяет наличие ошибок при вызове write()
вместо того, чтобы их лишить.
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);
}
}
Это не наносит вреда, но на самом деле не требуется большинство серверов (и вы можете даже использовать один '\ n' вместо' \ r \ n'). – kriss
@caf 'fgets()' только заполняет символы 'size - 1' данными и всегда добавляет нуль, поэтому' -3' в порядке. «Write» включает в себя длину отправляемых данных, поэтому строка не должна заканчиваться с NUL-завершением. Тем не менее, 'strcpy()' (или, может быть, 'strcat()'), вероятно, лучше. – llasram
Согласившись с необходимостью nul-terminator для 'write()' - вместо этого использовать 'memcpy()'. – caf