免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3110 | 回复: 5
打印 上一主题 下一主题

IPv[46]简单TCP服务器客户端[200行打造] [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-01-30 07:02 |只看该作者 |倒序浏览

  1. /**********************************************
  2. 作者:Minuit
  3. 时间:2007年01月30日 星期二 04时36分08秒
  4. 文件名:tcp6servcli.c
  5. 描述:tcp服务器客户端
  6. **********************************************/
  7. #include<stdio.h>
  8. #include<stdlib.h>
  9. #include<unistd.h>
  10. #include<string.h>
  11. #include<errno.h>
  12. #include <sys/types.h>
  13. #include <sys/socket.h>
  14. #include <netdb.h>
  15. enum {
  16.         NETINIT_TCPSERV=1,  /*创建一个tcp已经监听套接口服务器*/
  17.         NETINIT_TCPCLI,         /*创建一个tcp已经连接套接口客户端*/
  18.         NETINIT_TCPCLIBIND,  /*创建一个tcp已经连接并且绑定本IP地址和端口的客户端*/
  19.         NETINIT_UDPSERV,   /*创建一个udp已经绑定套接口服务器*/
  20.         NETINIT_UDPCLI,    /*创建一个udp客户端*/
  21.         NETINIT_UDPCLICONN,  /*创建一个udp并且已经连接服务器套接口客户端*/
  22.         NETINIT_BACKLOG=100  
  23. };
  24. /*
  25. netinit 所能干的事情就上面那几种
  26. 第一个参数主机名或者ip地址(当建服务器时此参数可为空默认BING一个通配的ipv6地址)
  27. 第二个参数服务名在/etc/services或者端口号(不能为空)
  28. 第三,四参数就不用介绍了说说有什么用处当建立服务器时他返回相关协议的地址长度和地址结构两个都可能为空
  29. 根据须要比如建一个服务器当调用accept(2)的时候如果想返回客户机的信息那就要用到第四个参数地址长度(注:accept后两个参数是可选的)又比如客户端想用sendto发送信息到服务器那就可能须要一个服务器的地址如果你填了第三个参数它就返回一个服器的地址结构这个还是很智能的(^_^)当然像udp服务器只有调用recvfrom或者recvmsg才须要第四个参数,udp客户端只用用sendto或者sendmsg时会用到第三个参数总之只要第三,四个参数不空它就会给你填上你想要的东西如果为空那就是你不想让他返回什么(你也可以过后调用get[sock|peer]name系统调用获取你想要的结构信息)
  30. 第四个参数已经说过了
  31. */
  32. int netinit(const char *host,const char *serv,struct sockaddr *addr,socklen_t *addrlen,int flags)
  33. {
  34.         struct addrinfo hist,*res,*save;   
  35.         int sockfd,on=1,errcode;
  36.         bzero(&hist,sizeof(struct addrinfo));
  37.         if(serv==NULL)
  38.                 return -1;
  39.         hist.ai_family=AF_UNSPEC;
  40.         switch(flags)
  41.           {
  42.                 case NETINIT_TCPSERV:
  43.                 case NETINIT_UDPSERV:
  44.                         hist.ai_flags=AI_PASSIVE;   /*如果是服务器的话就设置被动模式*/
  45.                         break;
  46.                 case NETINIT_TCPCLI:
  47.                 case NETINIT_UDPCLI:
  48.                 case NETINIT_UDPCLICONN:
  49.                 case NETINIT_TCPCLIBIND:
  50.                         hist.ai_flags=AI_CANONNAME;  /*如果是客户端那就addrinfo结构组成的链表第一个结构里面的一个成员被填充主机名*/
  51.                         break;
  52.                 default:
  53.                         errno=ENOTSUP;  /*不支持有时间把unix域加上*/
  54.                         return -1;
  55.           }
  56.         switch(flags)
  57.           {
  58.                 case NETINIT_TCPCLI:
  59.                 case NETINIT_TCPSERV:
  60.                 case NETINIT_TCPCLIBIND:
  61.                         hist.ai_socktype=SOCK_STREAM;  /*udp还是tcp*/
  62.                         break;
  63.                 case NETINIT_UDPSERV:
  64.                 case NETINIT_UDPCLI:
  65.                 case NETINIT_UDPCLICONN:
  66.                         hist.ai_socktype=SOCK_DGRAM;
  67.                         break;
  68.                 default:
  69.                         errno=ENOTSUP;
  70.                         return -1;
  71.           }
  72.         if((errcode=getaddrinfo(host,serv,&hist,&res))!=0)
  73.           {
  74.                 fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(errcode));
  75.                 return -1;
  76.           }
  77.         save=res;  /*保存res待会好毁了它*/
  78.         do
  79.           {
  80.                /*创建套接口不管是服务器还是客户端的共同点必须要做的*/
  81.                 if((sockfd=socket(res->ai_family,res->ai_socktype,res->ai_protocol))>0)
  82.                   {
  83.                         /*要绑定地址的者在这里做*/
  84.                         if(flags==NETINIT_TCPSERV||flags==NETINIT_TCPCLIBIND||flags==NETINIT_UDPSERV)
  85.                           {
  86.                                 if(flags!=NETINIT_TCPCLIBIND)
  87.                                         if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))!=0)  /*给服务器设置端口重用*/
  88.                                                 return -1;
  89.                                 if(bind(sockfd,res->ai_addr,res->ai_addrlen)==0)
  90.                                         break;
  91.                           }
  92.                         else
  93.                           {
  94.                                /*要建连接的者在这里做*/
  95.                                 if(flags!=NETINIT_UDPCLI)
  96.                                   {
  97.                                         if(connect(sockfd,res->ai_addr,res->ai_addrlen)==0)
  98.                                                 break;
  99.                                   }
  100.                                 else
  101.                                         break;
  102.                           }/*如果成功建立套接口那就先出去不然等到链表里的结构都试完了就出去*/
  103.                   }
  104.                 close(sockfd);  /*如果创建不成功的话先关闭再说再试下面一个结构*/
  105.           } while((res=res->ai_next)!=NULL);  
  106.         if(res==NULL)  /*如果失败了返回*/
  107.                 return -1;
  108.         if(addr!=NULL)  
  109.                 memcpy(addr,res->ai_addr,res->ai_addrlen);
  110.         if(addrlen!=NULL)
  111.                 *addrlen=res->ai_addrlen;
  112.         freeaddrinfo(save);  /*释放addrinfo链表之前已经保存了地址*/
  113.         if(flags!=NETINIT_TCPSERV)  /*如果是tcp服务器的话还有一点事没做其它的返回*/
  114.                 return sockfd;
  115.         else
  116.                 if(listen(sockfd,NETINIT_BACKLOG)!=0)     /*监听套接口*/
  117.                         return -1;
  118.         return sockfd;
  119. }
  120. void usage(char *arg)
  121. {
  122.         fprintf(stderr,\
  123.                         "Usage:%s [-cs] [<ip or hostname>] <port or server>\n",\
  124.                         arg);
  125.         exit(-1);
  126. }
  127. int main(int argc,char **argv)
  128. {
  129.         struct sockaddr *addr;
  130.         socklen_t  addrlen;
  131.         int servfd,clifd,pid,c,mode=1;
  132.         opterr=0;
  133.         while((c=getopt(argc,argv,"cs"))!=EOF)
  134.           {
  135.                 switch(c)
  136.                   {
  137.                         case 'c':
  138.                                 mode=0;
  139.                                 break;
  140.                         case 's':
  141.                                 mode=1;
  142.                                 break;
  143.             default:
  144.                                 usage(argv[0]);
  145.                   }
  146.           }
  147.         if((addr=malloc(sizeof(struct sockaddr_in6)))==NULL)
  148.                 return -1;
  149.         c=argc-optind;
  150.         switch(c)
  151.           {
  152.                 case 1:
  153.                         if(!mode)
  154.                                 usage(argv[0]);
  155.                         servfd=netinit(NULL,argv[optind],addr,NULL,NETINIT_TCPSERV);
  156.                         break;
  157.                 case 2:
  158.                         servfd=netinit(argv[optind],argv[optind+1],addr,mode?NULL:&addrlen,mode?NETINIT_TCPSERV:NETINIT_TCPCLI);
  159.                         break;
  160.                 default:
  161.                         usage(argv[0]);
  162.           }
  163.         if(servfd==-1)
  164.                 usage(argv[0]);
  165.         if(mode)
  166.           {
  167.                 while(1)
  168.                   {
  169.                         if((clifd=accept(servfd,addr,&addrlen))<=0)
  170.                           {
  171.                                 fprintf(stderr,"accept:%s\n",strerror(errno));
  172.                                 return -1;
  173.                           }
  174.                         if((pid=fork())<0)
  175.                           {
  176.                                 fprintf(stderr,"fork:%s\n",strerror(errno));
  177.                                 return -1;
  178.                           }
  179.                         else if(pid==0)
  180.                           {
  181.                                 char buf[BUFSIZ];
  182.                                 int n;
  183.                                 while((n=read(clifd,buf,BUFSIZ))>0)
  184.                                         write(clifd,buf,n);
  185.                                 exit(0);
  186.                           }
  187.                         close(clifd);
  188.                   }
  189.           }
  190.         else
  191.           {
  192.                 int n;
  193.                 char buf[BUFSIZ];
  194.                 while(1)
  195.                   {
  196.                 if(n=read(STDIN_FILENO,buf,BUFSIZ))
  197.                   {
  198.                   if(write(servfd,buf,n)!=n)
  199.                                   break;
  200.                   }
  201.                 else
  202.                         break;
  203.                 if((n=read(servfd,buf,BUFSIZ))>0)
  204.                   {
  205.                          if(write(STDOUT_FILENO,buf,n)!=n)
  206.                                  break;
  207.                   }
  208.                 else
  209.                         break;
  210.                   }
  211.                 close(servfd);
  212.           }
  213.         return 0;
  214. }
复制代码


看了一步一步网络编程*不知道还有人爱好这个
就把我前几个月写的通用的网络初始化函数截下来写这个二百行的服务器+客户端简单网络程序
让大家也偷偷懒写ipv[46]服务器客户端也就那两下子而且主机名IP地址 服务端口都可以用
我就不试范怎么用(4点多钟来的才写了这么多注释^_^!)
就说一下两个命令行参数
-c  以客户端起动
-s  以服务器起动
如果没有选项的话那默认就服务器
服务器还最少要一个参数那就是端口或者服务名如果两个参数那就绑定第一个参数所指的ip地址
客户端必须两个参数并且-c选项不能少
就这么多了
如果有什么不足之处还请指出^_^

[ 本帖最后由 lovesaka 于 2007-1-30 07:13 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-01-30 09:26 |只看该作者
谢谢LZ,学习哈

论坛徽章:
0
3 [报告]
发表于 2007-01-30 17:03 |只看该作者
这个通用的与协议无关函数不好用吗
怎么没大侠出来指点一下呀^_^!

论坛徽章:
0
4 [报告]
发表于 2007-01-30 19:29 |只看该作者
多谢lz共享,只是我的水平还没有到那个指点的水平上 ~~
等以后进步了再说吧,呵呵

论坛徽章:
0
5 [报告]
发表于 2007-02-03 02:08 |只看该作者
多谢两位支持
看来这东西使用上还是有点麻烦
但是他确实可以去掉很多每次老是要写的代码,又是IPV4,IPV6都能用的麻烦也是值得的^_^

论坛徽章:
0
6 [报告]
发表于 2007-02-03 12:00 |只看该作者
支持
虽然没看代码
但感觉是非常实用的东西啊
收藏了将来没准能用上
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP