Chinaunix首页 | 论坛 | 博客
  • 博客访问: 563107
  • 博文数量: 142
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1452
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-12 16:28
文章分类

全部博文(142)

文章存档

2016年(10)

2015年(60)

2014年(72)

我的朋友

分类: C/C++

2014-09-22 15:28:58

最近在学习getsockname的用法时,想通过inet_ntoa将网络序的地址转换成为字符串,通过printf输出,结果发现运行后直接出现了coredump,代码如下:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. //#include <arpa/inet.h>
  9. #define BUFLEN 128
  10. int main()
  11. {
  12.     int fd;
  13.     int new_fd;
  14.     struct sockaddr_in bind_addr;
  15.     struct sockaddr_in local_addr;
  16.     socklen_t socklen;
  17.     int ret;
  18.     FILE *fp;
  19.     char buf[BUFLEN];
  20.     

  21.     fd = socket(AF_INET, SOCK_STREAM, 0);
  22.     if(fd == -1) {
  23.         printf("socket create failed");
  24.         return -1;
  25.     }
  26.     memset(&bind_addr,0,sizeof(bind_addr));
  27.     bind_addr.sin_family = AF_INET;
  28. // bind_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  29.     bind_addr.sin_port = htons(9000);
  30.     ret = bind(fd, (struct sockaddr*)&bind_addr, (socklen_t)sizeof(bind_addr));
  31.     if(ret < 0) {
  32.         printf("bind socket failed,ret=%d,errno=%d\n",ret,errno);
  33.         close(fd);
  34.         return -1;
  35.     }
  36.     socklen = sizeof(local_addr);
  37.     if(getsockname(fd,(struct sockaddr*)&local_addr,&socklen) < 0)
  38.         printf("----getsockname after bind error :%d\n",errno);
  39.     
  40.     printf("after bind local addr=%s,port=%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
  41.    

  42.     ret = listen(fd,1024);
  43.     if(ret < 0) {
  44.         printf("listen socket failed");
  45.         close(fd);
  46.         return -1;
  47.     }

  48.     for(;;) {
  49.         new_fd = accept(fd,NULL,NULL);
  50.         if(new_fd < 0) {
  51.             printf("accept error");
  52.             exit(1);
  53.         }
  54.        socklen = sizeof(local_addr);
  55.        getsockname(new_fd,(struct sockaddr*)&local_addr,&socklen);
  56.       printf("after accept local addr = %s,port=%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
  57.         if((fp = popen("/usr/bin/uptime","r")) == NULL) {
  58.             sprintf(buf,"error: %s\n",strerror(errno));
  59.             send(new_fd, buf, strlen(buf), 0);
  60.         }else {
  61.             while(fgets(buf,BUFLEN,fp) != NULL)
  62.                 send(new_fd, buf, strlen(buf),0);
  63.             pclose(fp);
  64.         }
  65.         close(new_fd);
  66.     }
  67.     exit(0);
  68. }
编译运行:
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后的监听端口而言。


阅读(1454) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~