最近在学习getsockname的用法时,想通过inet_ntoa将网络序的地址转换成为字符串,通过printf输出,结果发现运行后直接出现了coredump,代码如下:
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <string.h>
-
#include <errno.h>
-
#include <sys/socket.h>
-
#include <netinet/in.h>
-
//#include <arpa/inet.h>
-
#define BUFLEN 128
-
int main()
-
{
-
int fd;
-
int new_fd;
-
struct sockaddr_in bind_addr;
-
struct sockaddr_in local_addr;
-
socklen_t socklen;
-
int ret;
-
FILE *fp;
-
char buf[BUFLEN];
-
-
-
fd = socket(AF_INET, SOCK_STREAM, 0);
-
if(fd == -1) {
-
printf("socket create failed");
-
return -1;
-
}
-
memset(&bind_addr,0,sizeof(bind_addr));
-
bind_addr.sin_family = AF_INET;
-
// bind_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-
bind_addr.sin_port = htons(9000);
-
ret = bind(fd, (struct sockaddr*)&bind_addr, (socklen_t)sizeof(bind_addr));
-
if(ret < 0) {
-
printf("bind socket failed,ret=%d,errno=%d\n",ret,errno);
-
close(fd);
-
return -1;
-
}
-
socklen = sizeof(local_addr);
-
if(getsockname(fd,(struct sockaddr*)&local_addr,&socklen) < 0)
-
printf("----getsockname after bind error :%d\n",errno);
-
-
printf("after bind local addr=%s,port=%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
-
-
-
ret = listen(fd,1024);
-
if(ret < 0) {
-
printf("listen socket failed");
-
close(fd);
-
return -1;
-
}
-
-
for(;;) {
-
new_fd = accept(fd,NULL,NULL);
-
if(new_fd < 0) {
-
printf("accept error");
-
exit(1);
-
}
-
socklen = sizeof(local_addr);
-
getsockname(new_fd,(struct sockaddr*)&local_addr,&socklen);
-
printf("after accept local addr = %s,port=%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
-
if((fp = popen("/usr/bin/uptime","r")) == NULL) {
-
sprintf(buf,"error: %s\n",strerror(errno));
-
send(new_fd, buf, strlen(buf), 0);
-
}else {
-
while(fgets(buf,BUFLEN,fp) != NULL)
-
send(new_fd, buf, strlen(buf),0);
-
pclose(fp);
-
}
-
close(new_fd);
-
}
-
exit(0);
-
}
编译运行:
gwwu@hz-dev2.wgw.com:~/test/socket>gcc -g socket_server.c -o server
gwwu@hz-dev2.wgw.com:~/test/socket>./server
段错误 (core dumped)
gwwu@hz-dev2.wgw.com:~/test/socket>
用gdb跟踪发现是printf在输出inet_ntoa时出错了,查了很久没法发现原因,期间也怀疑过空指针。
查阅相关资料,发现通过在编译选项中添加-Wall选项(显示所有告警信息)时,提示了关于inet_ntoa函数的warning。
gwwu@hz-dev2.wgw.com:~/test/socket>gcc -g socket_server.c -o server -Wall
socket_server.c: 在函数‘main’中:
socket_server.c:41: 警告:隐式声明函数‘inet_ntoa’
socket_server.c:41: 警告:格式‘%s’需要类型‘char *’,但实参 2 的类型为‘int’
socket_server.c:59: 警告:格式‘%s’需要类型‘char *’,但实参 2 的类型为‘int’
gwwu@hz-dev2.wgw.com:~/test/socket>
从中可以看出warning中提示,由于是隐形声明,inet_ntoa返回的是int类型,但是我们需要的是char*, 所有需要显示声明inet_ntoa,
解决方法就是调用头文件
将上面代码中的#include 注释行打开,重新编译运行:
gwwu@hz-dev2.aerohive.com:~/test/socket>gcc -g socket_server.c -o server -Wall
gwwu@hz-dev2.aerohive.com:~/test/socket>./server
after bind local addr=0.0.0.0,port=9000
after accept local addr = 127.0.0.1,port=9000
上面的例子也说明了一个问题,对于getsockname来说,服务器端的本端地址是对于accept以后新的连接socket而言的,而不是对于listen后的监听端口而言。
阅读(1445) | 评论(0) | 转发(0) |