LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 3993|回复: 10

学习网络编程遇到问题,已解决,谢谢各位!

[复制链接]
发表于 2007-7-30 02:13:38 | 显示全部楼层 |阅读模式
小弟刚开始学C语言,问题很菜,但google,百度没搜到有用的结果,可能有用的没看到吧
我抄了GNU/Linux编程指南(第二版)上网络编程的第一个例子,最简单的服务器server.c

  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <arpa/inet.h>
  5. #include <netdb.h>

  6. int port = 8000;

  7. void main(){
  8.         //struct socketaddr_in sin;
  9.         struct socketaddr_in sin;
  10.         //struct socketaddr_in pin;
  11.          struct socketaddr_in sin;
  12.         int sock_desc;
  13.         int tmp_sock_desc;
  14.         int address_size;
  15.         char buf[16384];
  16.         int i, len;
  17.         //新加入
  18.         address_size = sizeof(pin);

  19.         //创建套接口
  20.         sock_desc = socket(AF_INET,SOCK_STREAM,0);
  21.         if(sock_desc == -1){
  22.                 perror("call to socket");
  23.                 exit(1);
  24.                 }
  25.        
  26.         //初始化套接口
  27.         bzero(&sin,sizeof(sin));
  28.         sin.sin_family = AF_INET;
  29.         sin.sin_addr.s_addr = INADDR_ANY;
  30.         sin.sin_port = htons(port);
  31.        
  32.         //绑定
  33.         if(bind(sock_desc,(struct socketaddr *) &sin,sizeof(sin)) == -1){
  34.                 perror("call to bind");
  35.                 exit(1);
  36.                 }
  37.        
  38.         //开始监听
  39.         if(listen(sock_desc,20) == -1){
  40.                 perror("call to listen");
  41.                 exit(1);
  42.                 }
  43.         printf("Accepting connections ...\n");
  44.        
  45.         while(1){
  46.                 //创建临时套接口
  47.                 tmp_sock_desc = accept(sock_desc,(struct sockaddr *) &pin,&address_size);
  48.                 if(tmp_sock_desc == -1){
  49.                         perror("call to accept");
  50.                         exit(1);
  51.                         }
  52.                
  53.                 //接收数据
  54.                 if(recv(tmp_sock_desc,buf,16384,0) == -1){
  55.                         perror("call to recv");
  56.                         exit(1);
  57.                         }
  58.                 printf("received from client %s\n",buf);

  59.                 //处理接收数据
  60.                 len = strlen(buf);
  61.                 for(i=0;i<=len;i++){
  62.                         buf[i] = toupper(buf[i]);
  63.                         }
  64.                
  65.                 //发送数据
  66.                 if(send(tmp_sock_desc,buf,len,0) == -1){
  67.                         perror("call to send");
  68.                         exit(1);
  69.                         }
  70.                 close(tmp_sock_desc);
  71.                 }
  72.         }

复制代码

make server
出现以下错误:

  1. etch:~/cs# make server
  2. cc     server.c   -o server
  3. server.c: In function ‘main’:
  4. server.c:10: error: storage size of ‘sin’ isn’t known
  5. server.c:11: error: storage size of ‘pin’ isn’t known
  6. server.c:22: warning: incompatible implicit declaration of built-in function ‘exit’
  7. server.c:26: warning: incompatible implicit declaration of built-in function ‘bzero’
  8. server.c:34: warning: incompatible implicit declaration of built-in function ‘exit’
  9. server.c:40: warning: incompatible implicit declaration of built-in function ‘exit’
  10. server.c:49: warning: incompatible implicit declaration of built-in function ‘exit’
  11. server.c:55: warning: incompatible implicit declaration of built-in function ‘exit’
  12. server.c:60: warning: incompatible implicit declaration of built-in function ‘strlen’
  13. server.c:68: warning: incompatible implicit declaration of built-in function ‘exit’
  14. server.c:9: warning: return type of ‘main’ is not ‘int’
  15. make: *** [server] Error 1
复制代码

问题应该出在sockaddr_in这个结构,它的声明在netinet/in.h

  1. struct sockaddr_in
  2.   {
  3.     __SOCKADDR_COMMON (sin_);
  4.     in_port_t sin_port;                 /* Port number.  */
  5.     struct in_addr sin_addr;            /* Internet address.  */

  6.     /* Pad to size of `struct sockaddr'.  */
  7.     unsigned char sin_zero[sizeof (struct sockaddr) -
  8.                            __SOCKADDR_COMMON_SIZE -
  9.                            sizeof (in_port_t) -
  10.                            sizeof (struct in_addr)];
  11.   };
复制代码

这个错误是什么意思?是不是我少写了什么东西?

  1. error: storage size of ‘sin’ isn’t known
复制代码
发表于 2007-7-30 09:04:01 | 显示全部楼层
struct socketaddr_in sin;
应该为
struct sockaddr_in sin;
吧. 后面的pin也是一样的.
可能你抄错了.
回复 支持 反对

使用道具 举报

发表于 2007-7-30 10:05:31 | 显示全部楼层
早啊,scutan兄,楼主可以stdlib.h和string.h加上就不会有警告了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-7-30 11:27:57 | 显示全部楼层
谢谢楼上两位,的确是抄错了,狂汗。。。但是为什么不报错未定义呢?
还有一个问题:
改了之后能编译运行,但在接收到请求的时候accept出错退出:
call to accept: Invalid argument
我估计是&address_size的问题,于是我给address_size赋值sizeof(pin),这个服务器终于可以正常运行了。我又仔细看了一下原文,没找到给address_size赋值的地方,难道又看错了?
回复 支持 反对

使用道具 举报

发表于 2007-7-30 15:09:52 | 显示全部楼层
Post by geoffrey001
谢谢楼上两位,的确是抄错了,狂汗。。。但是为什么不报错未定义呢?
还有一个问题:
改了之后能编译运行,但在接收到请求的时候accept出错退出:
call to accept: Invalid argument
我估计是&address_size的问题,于是我给address_size赋值sizeof(pin),这个服务器终于可以正常运行了。我又仔细看了一下原文,没找到给address_size赋值的地方,难道又看错了?
嗯.我也看到有的机器上需要为这个数赋值的情况.
你用的什么系统?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-7-30 16:01:27 | 显示全部楼层
Debian Etch kernel 2.6.18-5-686
机器配置见签名档。
回复 支持 反对

使用道具 举报

发表于 2007-7-30 16:04:21 | 显示全部楼层
Post by geoffrey001
Debian Etch kernel 2.6.18-5-686
机器配置见签名档。


哦.呵呵.没仔细看你的签名档.
我用的FC.没有出现你说的那种情况.不过我以前的确是看到过别人说的,必须将accept第三个参数赋值之后才可以成功调用.是在chinaunix这个论坛上面看到的.但具体哪个贴子一下子还真找不到了.
回复 支持 反对

使用道具 举报

发表于 2007-7-30 17:33:11 | 显示全部楼层
accept的第三个参数是一个值-结果型参数,如果你给定了第二个参数,也就是说你需要回带客户端信息,那么你必须给出第三个参数,表示特定的长度,当函数返回时,会往第三个参数里填入真实的客户端地址长度。
关于值-结果型参数还有很多例子,建议你google一下。

另外,如果你不想给出第三个参数,可以将accept的后两个参数都设置为NULL,这样就不会取得客户端的信息。
回复 支持 反对

使用道具 举报

发表于 2007-7-30 19:19:19 | 显示全部楼层
Post by ratcj
accept的第三个参数是一个值-结果型参数,如果你给定了第二个参数,也就是说你需要回带客户端信息,那么你必须给出第三个参数,表示特定的长度,当函数返回时,会往第三个参数里填入真实的客户端地址长度。
关于值-结果型参数还有很多例子,建议你google一下。

另外,如果你不想给出第三个参数,可以将accept的后两个参数都设置为NULL,这样就不会取得客户端的信息。



楼主的原因不是你说的这种,他的原因是对于下面的写法
accept(sockfd, (struct sockaddr*)&sin, &address_size);
必须在使用之前显式地使address_size的值为sizeof(sin);才运行正常.即
在调用accpet()函数之前还需要再进行一次赋值.
address_size = sizeof(pin);
回复 支持 反对

使用道具 举报

发表于 2007-7-31 09:38:59 | 显示全部楼层
理解错了,嘿嘿,见谅见谅。

不过再看一下楼主的代码里,要给accept赋值的第三个参数是用int申明的,而accept的第三个参数是socklen_t *。
不知道改变一下类型之后可不可以不需要sizeof(sin)。
另外根据不同的机器,socklen_t也许就是int,包括上头文件应该没有问题吧。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表