我有一个小程序让我通过TCP连接;并进行文字交流:
#include <arpa/inet.h>
#include <error.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define BUFLEN 1024
int connect_to(char *host, int port) {
int sd;
struct sockaddr_in addr;
fd_set sfds;
struct timeval tv;
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd == -1) return sd;
if (fcntl(sd, F_SETFL, O_NONBLOCK) == -1) return -2;
memset(&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
if (inet_pton(AF_INET, host, &addr.sin_addr) != 1)
return -3;
addr.sin_port = htons(port);
connect(sd, (struct sockaddr *) &addr, sizeof (addr));
FD_ZERO(&sfds);
FD_SET(sd, &sfds);
tv.tv_sec = 4;
tv.tv_usec = 0;
if (select(sd + 1, NULL, &sfds, NULL, &tv)) return sd;
return -4;
}
int resolve(char *host) {
struct addrinfo hints, *servinfo;
struct in_addr addr;
char *addr_tmp;
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
rv = getaddrinfo(host, NULL, &hints, &servinfo);
if (rv) return -1;
addr.s_addr = ((struct sockaddr_in*)servinfo->ai_addr)->sin_addr.s_addr;
addr_tmp = inet_ntoa(addr);
memcpy(host, addr_tmp, strlen(addr_tmp));
freeaddrinfo(servinfo);
return 0;
}
sig_atomic_t run = 1;
void sig_handler(int sig) { run = 0; }
int transfer(int fd_in, char *buf, int buf_len, int fd_out) {
int len = read(fd_in, buf, buf_len);
return len > -1? write(fd_out, buf, len) - len: -1;
}
int main(int argc, char **argv) {
int sd, rv;
fd_set fds;
struct timeval tv;
char buffer[BUFLEN];
char host[256], *port;
memcpy(host, argv[1], strlen(argv[1]) + 1);
port = argv[2];
sd = connect_to(host, atoi(port));
if (sd < 0) {
if (resolve(host) < 0) return 1;
else sd = connect_to(host, atoi(port));
if (sd < 0) return 2;
}
write(STDOUT_FILENO, "connected\n", 11);
signal(SIGINT, sig_handler);
FD_ZERO(&fds);
tv.tv_sec = 0;
tv.tv_usec = 100000;
while (run) {
FD_SET(sd, &fds);
FD_SET(STDIN_FILENO, &fds);
(void)select(sd + 1, &fds, NULL, NULL, &tv);
if (FD_ISSET(STDIN_FILENO, &fds)) rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd);
if (FD_ISSET(sd, &fds)) rv = transfer(sd, buffer, BUFLEN, STDOUT_FILENO);
if (rv < 0) return 3;
}
close(sd);
return 0;
}
如果我输入$ ./client google.com 80
,地址会解析,我输入GET /
,然后我获得该流的转储。
但是,如果我输入$ ./client towel.blinkenlights.nl 23
;程序退出。
$ echo $?
2
...告诉我resolve
没有将有效数据返回connect_to
。我不明白为什么。
答案 0 :(得分:1)
问题在于:
memcpy(host, addr_tmp, strlen(addr_tmp));
您不会终止字符串。尝试使用
strcpy(host, addr_tmp);
否则,原始主机名的其余部分将保留并使IP地址(1.2.3.4nkenlights.nl
或类似地址)无效。 google.com足够短,可以完全覆盖,偶然IP地址在那里被终止。