TCP的socket连接示例(linux&windows)

Made In Zeal 转载请保留原始链接: http://www.zeali.net/entry/13

 用C实现的TCP socket连接/读/写操作。采用fcntl设置非阻塞式连接以实现connect超时处理;采用select方法来设置socket读写超时。此示例可被编译运行于Windows/unix系统。

源文件connector.c

原来的代码在windows下编译不通过,今天qzj问起才发现。因为加了异步的处理,没有对这部分代码进行兼容性处理。本着做学问一丝不苟嘀精神,重新修改了一下源代码。以下代码在VC++6和linux下编译执行通过 :)

-------------------------------------------------------------------------------------------------------------------------------
  1. /* 
  2.  
  3.  * on Unix: 
  4.  
  5.  *    cc -c connector.c 
  6.  
  7.  *    cc -o connector connector.o 
  8.  
  9.  * 
  10.  
  11.  * on Windows NT: 
  12.  
  13.  *    open connector.c in Visual Studio 
  14.  
  15.  *    press 'F7' to link -- a project to be created 
  16.  
  17.  *    add wsock32.lib to the link section under project setting 
  18.  
  19.  *    press 'F7' again 
  20.  
  21.  * 
  22.  
  23.  * running: 
  24.  
  25.  *    type 'connector' for usage 
  26.  
  27.  */  
  28.   
  29.   
  30. #include <stdio.h>  
  31.   
  32. #include <stdlib.h>  
  33.   
  34. #include <string.h>  
  35.   
  36. #include <stdarg.h>  
  37.   
  38. #include <errno.h>  
  39.   
  40. #include <fcntl.h>  
  41.   
  42. #ifdef WIN32  
  43.   
  44. #include <winsock2.h>  
  45.   
  46. #else  
  47.   
  48. #include <unistd.h>  
  49.   
  50. #include <sys/types.h>  
  51.   
  52. #include <sys/socket.h>  
  53.   
  54. #include <sys/ioctl.h>  
  55.   
  56. #include <netinet/in.h>  
  57.   
  58. #include <arpa/inet.h>  
  59.   
  60. #include <netdb.h>  
  61.   
  62. #endif  
  63.   
  64.   
  65. #ifndef INADDR_NONE  
  66.   
  67. #define INADDR_NONE     0xffffffff  
  68.   
  69. #endif  
  70.   
  71. #define MAX_STRING_LEN  1024  
  72.   
  73. #define BUFSIZE  2048  
  74.   
  75.   
  76. #ifndef WIN32  
  77.   
  78. #define SOCKET int  
  79.   
  80. #else  
  81.   
  82. #define errno WSAGetLastError()  
  83.   
  84. #define close(a) closesocket(a)  
  85.   
  86. #define write(a, b, c) send(a, b, c, 0)  
  87.   
  88. #define read(a, b, c) recv(a, b, c, 0)  
  89.   
  90. #endif  
  91.   
  92.   
  93. char buf[BUFSIZE];  
  94.   
  95.   
  96. static char i_host[MAX_STRING_LEN];  /* site name */  
  97.   
  98. static char i_port[MAX_STRING_LEN];  /* port number */  
  99.   
  100.   
  101. void err_doit(int errnoflag, const char *fmt, va_list ap);  
  102.   
  103. void err_quit(const char *fmt, ...);  
  104.   
  105. int tcp_connect(const char *host, const unsigned short port);  
  106.   
  107. void print_usage();  
  108.   
  109.   
  110. //xnet_select x defines  
  111.   
  112. #define READ_STATUS  0  
  113.   
  114. #define WRITE_STATUS 1  
  115.   
  116. #define EXCPT_STATUS 2  
  117.   
  118.   
  119. /* 
  120.  
  121. s    - SOCKET 
  122.  
  123. sec  - timeout seconds 
  124.  
  125. usec - timeout microseconds 
  126.  
  127. x    - select status 
  128.  
  129. */  
  130.   
  131. SOCKET xnet_select(SOCKET s, int sec, int usec, short x)  
  132.   
  133. {  
  134.   
  135.  int st = errno;  
  136.   
  137.  struct timeval to;  
  138.   
  139.  fd_set fs;  
  140.   
  141.  to.tv_sec = sec;  
  142.   
  143.  to.tv_usec = usec;  
  144.   
  145.  FD_ZERO(&fs);  
  146.   
  147.  FD_SET(s, &fs);  
  148.   
  149.  switch(x){  
  150.   
  151.   case READ_STATUS:  
  152.   
  153.   st = select(s+1, &fs, 0, 0, &to);  
  154.   
  155.   break;  
  156.   
  157.   case WRITE_STATUS:  
  158.   
  159.   st = select(s+1, 0, &fs, 0, &to);  
  160.   
  161.   break;  
  162.   
  163.   case EXCPT_STATUS:  
  164.   
  165.   st = select(s+1, 0, 0, &fs, &to);  
  166.   
  167.   break;  
  168.   
  169.  }  
  170.   
  171.  return(st);  
  172.   
  173. }  
  174.   
  175.   
  176. int tcp_connect(const char *host, const unsigned short port)  
  177.   
  178. {  
  179.   
  180.     unsigned long non_blocking = 1;  
  181.   
  182.     unsigned long blocking = 0;  
  183.   
  184.     int ret = 0;  
  185.   
  186.     char * transport = "tcp";  
  187.   
  188.     struct hostent      *phe;   /* pointer to host information entry    */  
  189.   
  190.     struct protoent *ppe;       /* pointer to protocol information entry*/  
  191.   
  192.     struct sockaddr_in sin;     /* an Internet endpoint address  */  
  193.   
  194.     SOCKET s;                    /* socket descriptor and socket type    */  
  195.   
  196.     int error;  
  197.   
  198.   
  199. #ifdef WIN32  
  200.   
  201.     {  
  202.   
  203.         WORD wVersionRequested;  
  204.   
  205.         WSADATA wsaData;  
  206.   
  207.         int err;  
  208.   
  209.    
  210.   
  211.         wVersionRequested = MAKEWORD( 2, 0 );  
  212.   
  213.    
  214.   
  215.         err = WSAStartup( wVersionRequested, &wsaData );  
  216.   
  217.         if ( err != 0 ) {  
  218.   
  219.             /* Tell the user that we couldn't find a usable */  
  220.   
  221.             /* WinSock DLL.                               */  
  222.   
  223.             printf("can't initialize socket library/n");  
  224.   
  225.             exit(0);  
  226.   
  227.         }  
  228.   
  229.     }  
  230.   
  231. #endif      
  232.   
  233.       
  234.   
  235.     memset(&sin, 0, sizeof(sin));  
  236.   
  237.     sin.sin_family = AF_INET;  
  238.   
  239.       
  240.   
  241.     if ((sin.sin_port = htons(port)) == 0)  
  242.   
  243.         err_quit("invalid port /"%d/"/n", port);  
  244.   
  245.       
  246.   
  247.     /* Map host name to IP address, allowing for dotted decimal */  
  248.   
  249.     if ( phe = gethostbyname(host) )  
  250.   
  251.         memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);  
  252.   
  253.     else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )  
  254.   
  255.         err_quit("can't get /"%s/" host entry/n", host);  
  256.   
  257.       
  258.   
  259.     /* Map transport protocol name to protocol number */  
  260.   
  261.     if ( (ppe = getprotobyname(transport)) == 0)  
  262.   
  263.         err_quit("can't get /"%s/" protocol entry/n", transport);  
  264.   
  265.       
  266.   
  267.     /* Allocate a socket */  
  268.   
  269.     s = socket(PF_INET, SOCK_STREAM, ppe->p_proto);  
  270.   
  271.     if (s < 0)  
  272.   
  273.         err_quit("can't create socket: %s/n", strerror(errno));  
  274.   
  275.       
  276.   
  277.     /* Connect the socket with timeout */  
  278.   
  279. #ifdef WIN32  
  280.   
  281.     ioctlsocket(s,FIONBIO,&non_blocking);  
  282.   
  283. #else  
  284.   
  285.     ioctl(s,FIONBIO,&non_blocking);  
  286.   
  287. #endif  
  288.   
  289.     //fcntl(s,F_SETFL, O_NONBLOCK);  
  290.   
  291.     if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1){  
  292.   
  293.         struct timeval tv;   
  294.   
  295.         fd_set writefds;  
  296.   
  297.         // 设置连接超时时间  
  298.   
  299.         tv.tv_sec = 10; // 秒数  
  300.   
  301.         tv.tv_usec = 0; // 毫秒  
  302.   
  303.         FD_ZERO(&writefds);   
  304.   
  305.         FD_SET(s, &writefds);   
  306.   
  307.         if(select(s+1,NULL,&writefds,NULL,&tv) != 0){   
  308.   
  309.             if(FD_ISSET(s,&writefds)){  
  310.   
  311.                 int len=sizeof(error);   
  312.   
  313.                 //下面的一句一定要,主要针对防火墙   
  314.   
  315.                 if(getsockopt(s, SOL_SOCKET, SO_ERROR,  (char *)&error, &len) < 0)  
  316.   
  317.                     goto error_ret;   
  318.   
  319.                 if(error != 0)   
  320.   
  321.                     goto error_ret;   
  322.   
  323.             }  
  324.   
  325.             else  
  326.   
  327.                 goto error_ret; //timeout or error happen   
  328.   
  329.         }  
  330.   
  331.         else goto error_ret; ;   
  332.   
  333.   
  334. #ifdef WIN32  
  335.   
  336.         ioctlsocket(s,FIONBIO,&blocking);  
  337.   
  338. #else  
  339.   
  340.         ioctl(s,FIONBIO,&blocking);  
  341.   
  342. #endif  
  343.   
  344.   
  345.     }  
  346.   
  347.     else{  
  348.   
  349. error_ret:  
  350.   
  351.         close(s);  
  352.   
  353.         err_quit("can't connect to %s:%d/n", host, port);  
  354.   
  355.     }  
  356.   
  357.     return s;  
  358.   
  359. }  
  360.   
  361.   
  362. void err_doit(int errnoflag, const char *fmt, va_list ap)  
  363.   
  364. {  
  365.   
  366.     int errno_save;  
  367.   
  368.     char buf[MAX_STRING_LEN];  
  369.   
  370.   
  371.     errno_save = errno;   
  372.   
  373.     vsprintf(buf, fmt, ap);  
  374.   
  375.     if (errnoflag)  
  376.   
  377.         sprintf(buf + strlen(buf), ": %s", strerror(errno_save));  
  378.   
  379.     strcat(buf, "/n");  
  380.   
  381.     fflush(stdout);  
  382.   
  383.     fputs(buf, stderr);  
  384.   
  385.     fflush(NULL);  
  386.   
  387.     return;  
  388.   
  389. }  
  390.   
  391.   
  392. /* Print a message and terminate. */  
  393.   
  394. void err_quit(const char *fmt, ...)  
  395.   
  396. {  
  397.   
  398.     va_list ap;  
  399.   
  400.     va_start(ap, fmt);  
  401.   
  402.     err_doit(0, fmt, ap);  
  403.   
  404.     va_end(ap);  
  405.   
  406.     exit(1);  
  407.   
  408. }  
  409.   
  410.   
  411. #ifdef WIN32  
  412.   
  413. char *optarg;  
  414.   
  415.   
  416. char getopt(int c, char *v[], char *opts)  
  417.   
  418. {  
  419.   
  420.     static int now = 1;  
  421.   
  422.     char *p;  
  423.   
  424.   
  425.     if (now >= c) return EOF;  
  426.   
  427.   
  428.     if (v[now][0] == '-' && (p = strchr(opts, v[now][1]))) {  
  429.   
  430.         optarg = v[now+1];  
  431.   
  432.         now +=2;  
  433.   
  434.         return *p;  
  435.   
  436.     }  
  437.   
  438.   
  439.     return EOF;  
  440.   
  441. }  
  442.   
  443.   
  444. #else  
  445.   
  446. extern char *optarg;  
  447.   
  448. #endif  
  449.   
  450.   
  451. #define required(a) if (!a) { return -1; }  
  452.   
  453.   
  454. int init(int argc, char *argv[])  
  455.   
  456. {  
  457.   
  458.     char c;  
  459.   
  460.     //int i,optlen;  
  461.   
  462.     //int slashcnt;  
  463.   
  464.   
  465.     i_host[0]  =  '/0';  
  466.   
  467.     i_port[0]  =  '/0';  
  468.   
  469.   
  470.     while ((c = getopt(argc, argv, "h:p:?")) != EOF) {  
  471.   
  472.         if (c == '?')  
  473.   
  474.             return -1;  
  475.   
  476.         switch (c) {   
  477.   
  478.         case 'h':  
  479.   
  480.             required(optarg);  
  481.   
  482.             strcpy(i_host, optarg);  
  483.   
  484.             break;  
  485.   
  486.         case 'p':  
  487.   
  488.             required(optarg);  
  489.   
  490.             strcpy(i_port, optarg);  
  491.   
  492.             break;  
  493.   
  494.         default:  
  495.   
  496.             return -1;  
  497.   
  498.         }  
  499.   
  500.     }  
  501.   
  502.   
  503.     /*  
  504.  
  505.      * there is no default value for hostname, port number,  
  506.  
  507.      * password or uri 
  508.  
  509.      */  
  510.   
  511.     if (i_host[0] == '/0' || i_port[0] == '/0')  
  512.   
  513.         return -1;  
  514.   
  515.   
  516.     return 1;  
  517.   
  518. }  
  519.   
  520.   
  521. void print_usage()  
  522.   
  523. {  
  524.   
  525.     char *usage[] =  
  526.   
  527.     {  
  528.   
  529.         "Usage:",  
  530.   
  531.         "    -h    host name",  
  532.   
  533.         "    -p    port",  
  534.   
  535.         "example:",  
  536.   
  537.         "    -h 127.0.0.1 -p 4001",  
  538.   
  539.     };     
  540.   
  541.     int i;  
  542.   
  543.   
  544.     for (i = 0; i < sizeof(usage) / sizeof(char*); i++)  
  545.   
  546.         printf("%s/n", usage[i]);  
  547.   
  548.       
  549.   
  550.     return;  
  551.   
  552. }  
  553.   
  554.   
  555. int main(int argc, char *argv[])  
  556.   
  557. {  
  558.   
  559.     SOCKET fd;  
  560.   
  561.     int n;  
  562.   
  563.   
  564.     /* parse command line etc ... */  
  565.   
  566.     if (init(argc, argv) < 0) {  
  567.   
  568.         print_usage();  
  569.   
  570.         exit(1);  
  571.   
  572.     }  
  573.   
  574.   
  575.     buf[0] = '/0';  
  576.   
  577.   
  578.     /* pack the info into the buffer */       
  579.   
  580.     strcpy(buf, "HelloWorld");  
  581.   
  582.   
  583.     /* make connection to the server */  
  584.   
  585.     fd = tcp_connect(i_host, (unsigned short)atoi(i_port));  
  586.   
  587.   
  588.     if(xnet_select(fd, 0, 500, WRITE_STATUS)>0){  
  589.   
  590.         /* send off the message */  
  591.   
  592.         write(fd, buf, strlen(buf));  
  593.   
  594.     }  
  595.   
  596.     else{  
  597.   
  598.         err_quit("Socket I/O Write Timeout %s:%s/n", i_host, i_port);  
  599.   
  600.     }  
  601.   
  602.   
  603.     if(xnet_select(fd, 3, 0, READ_STATUS)>0){  
  604.   
  605.         /* display the server response */  
  606.   
  607.         printf("Server response:/n");  
  608.   
  609.         n = read(fd, buf, BUFSIZE);  
  610.   
  611.         buf[n] = '/0';  
  612.   
  613.         printf("%s/n", buf);  
  614.   
  615.     }  
  616.   
  617.     else{  
  618.   
  619.         err_quit("Socket I/O Read Timeout %s:%s/n", i_host, i_port);  
  620.   
  621.     }  
  622.   
  623.     close(fd);  
  624.   
  625.   
  626. #ifdef WIN32  
  627.   
  628.     WSACleanup();  
  629.   
  630. #endif  
  631.   
  632.   
  633.     return 0;  
  634.   
  635. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值