编译时,此代码允许我使用正确的IP地址作为程序参数连接到服务器。到目前为止,连接很好并且数据被发送到服务器,但是当我尝试使用recv()函数尝试以非阻塞模式收集数据时,我收到了分段错误。它总是出现在“接收数据......”行之后。
正如您所看到的,我为操作保留了5000字节的堆栈内存,而我正在测试只尝试读取一个字节而没有成功。 recv()不能用于堆栈内存吗?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
extern errno;
struct sockaddr_in a;
struct timeval tv;
fd_set wready;
long conntoserver(const char* ip,const char* data){
memset((char*)&a,0,sizeof(a));
if (inet_aton(ip,a.sin_addr.s_addr) == 0){printf("Can't set address\n");return -1;}
long s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if (s < 0){printf("Can't make socket\n");return -1;}
tv.tv_sec=1;tv.tv_usec=0;FD_ZERO(&wready);FD_SET(s,&wready);
//start non-blocking mode
if (fcntl(s,F_SETFL,O_NONBLOCK) < 0){printf("Can't make socket non-blocking\n");close(s);return -1;}
a.sin_family=AF_INET;a.sin_port=htons(80);long ret=connect(s,(struct sockaddr*)&a,sizeof(a));
if (ret < 0 && errno != EINPROGRESS){printf("Can't connect to IP. %s\n",strerror(errno));close(s);return -1;}
if (errno == EINPROGRESS){
printf("connection in progress...\n");
ret=select(s+1,NULL,&wready,NULL,&tv);
if (ret < 0){printf("select() error. %s\n",strerror(errno));close(s);return -1;}
if (ret==0){printf("select() timeout. %s\n",strerror(errno));close(s);return -1;}
}
unsigned long sz=strlen(data);
ssize_t ns=send(s,data,sz,0);
if (ns==sz){return s;}else{return -1;}
}
int main(int argc,char* argv[]){
if (argc < 2){printf("Format: %s < IP to connect to >\n",argv[0]);return -1;}
long s=conntoserver(argv[1],"GET / HTTP/1.1\nHost: example.com\n\n");
if (s < 0){printf("Error making server request. %s\n",strerror(errno));close(s);return -1;}
printf("receiving data...\n");
char b[5001];
ssize_t br=recv(s,b,1,0);
printf("br=%s\n",br);
close(s);
return 0;
}
答案 0 :(得分:0)
printf("br=%s\n",br);
应该是:
printf("br=%ld\n",br);
BTW - 我不得不修复一些问题来编译这段代码。您应该始终注意编译器警告。
答案 1 :(得分:0)
除了@keithmo指出的错误之外,你还有一个错误:
if (inet_aton(ip,a.sin_addr.s_addr) == 0){printf("Can't set address\n");return -1;}
inet_aton()
的第二个参数应该是struct in_addr
的指针,但是您传递的值为uint32_t
。实际上,该值初始化为零,因此结果很可能(但不确定)等同于传递NULL
指针。无论哪种方式,这都会产生不确定的行为,如果没有表现为段错误,我会感到惊讶。即使程序运行过程,您编写的调用也无法产生(显然)在变量a
中初始化地址所需的效果。
你想要的是
if (inet_aton(ip, &a.sin_addr) == 0) {
printf("Can't set address\n");
return -1;
}
为了善良,做免费使用空格和换行符。它们大大提高了代码的易读性。如果你做空,我可以借给你一些。