zoukankan      html  css  js  c++  java
  • 一个 Linux Windows下都可运行的 Socket 程序

    用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. }   
    636.   

    同时mark几个有用的url:

    http://people.web.psi.ch/rohrer_u/sample1.htm   Demo program for remote CAMAC access via TCP/IP

    http://www.lsword.net/code/list.asp?id=1383  将Socket应用程序从Unix向Windows移植中应注意的几点问题

  • 相关阅读:
    数据库镜像搭建
    关于开发人员数据库权限配置以及规范数据库升级流程
    带CheckBox列头的DataGridView
    查询整个数据库中某个特定值所在的表和字段的方法
    SQL Server 2008中获取数据库所有表及其字段名称、类型、长度的SQL
    关于已经上线项目的升级的启示
    SQL语句恢复数据库时一直显示“正在还原”
    带CheckBox列头的DataGridView(一)
    SQL Server中事务处理的注意事项
    group by 使用
  • 原文地址:https://www.cnblogs.com/cy163/p/1559513.html
Copyright © 2011-2022 走看看