socket编程——一个简单的例子(转)

原文地址:http://blog.csdn.net/wind19/article/details/6156339

从一个简单的使用TCP例子开始socket编程,其基本步骤如下:

server                                                  client

+++++++                                          ++++++++

创建socket                                          创建socket

+++++++                                          ++++++++

|                                                         |

|                                                         |

|                                                         |

+++++++                                          ++++++++

地址赋值(                                           地址赋值(

自己的地址)                                        服务器地址)

+++++++                                          ++++++++

|                                                         |

|                                                         |

|                                                         |

++++++++                                              |

用bind绑定                                                |

socket和地址                                             |

++++++++                                              |

|                                                         |

|                                                         |

|                                                         |

+++++++                                                 |

listen                                                         |

+++++++                                                  |

|                                                    ++++++++++

|   <------------------------------          connect 服务器

|                                                    ++++++++++

+++++++                                                  |

accept                                                        |

+++++++                                                  |

|                                                           |

|                                                    +++++++++

|                                                     recv 和send

|                                                     进行数据处理

|                                                     +++++++++

+++++++++                                                |

用accept得到                                                 |

的socket进行                                                 |

recv 和 send                                                 |

+++++++++                                                |

|                                                             |

|                                                             |

|                                                             |

+++++++++                                        +++++++++

close socket                                         close socket

+++++++++                                        +++++++++

根据以上步骤,服务器端的代码为

[cpp] view plaincopy

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <stdlib.h>
  6. #include <syslog.h>
  7. #include <errno.h>
  8. #define MAX_LISTEN_NUM 5
  9. #define SEND_BUF_SIZE 100
  10. #define RECV_BUF_SIZE 100
  11. #define LISTEN_PORT 1010
  12. int main()
  13. {
  14. int listen_sock = 0;
  15. int app_sock = 0;
  16. struct sockaddr_in hostaddr;
  17. struct sockaddr_in clientaddr;
  18. int socklen = sizeof(clientaddr);
  19. char sendbuf[SEND_BUF_SIZE] = {0};
  20. char recvbuf[RECV_BUF_SIZE] = {0};
  21. int sendlen = 0;
  22. int recvlen = 0;
  23. int retlen = 0;
  24. int leftlen = 0;
  25. char *ptr = NULL;
  26. memset((void *)&hostaddr, 0, sizeof(hostaddr));
  27. memset((void *)&clientaddr, 0, sizeof(clientaddr));
  28. hostaddr.sin_family = AF_INET;
  29. hostaddr.sin_port = htons(LISTEN_PORT);
  30. hostaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  31. listen_sock = socket(AF_INET, SOCK_STREAM, 0);
  32. if(listen_sock < 0)
  33. {
  34. syslog(LOG_ERR, "%s:%d, create socket failed", __FILE__, __LINE__);
  35. exit(1);
  36. }
  37. if(bind(listen_sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) < 0)
  38. {
  39. syslog(LOG_ERR, "%s:%d, bind socket failed", __FILE__, __LINE__);
  40. exit(1);
  41. }
  42. if(listen(listen_sock, MAX_LISTEN_NUM) < 0)
  43. {
  44. syslog(LOG_ERR, "%s:%d, listen failed", __FILE__, __LINE__);
  45. exit(1);
  46. }
  47. while(1)
  48. {
  49. app_sock = accept(listen_sock, (struct sockaddr *)&clientaddr, &socklen);
  50. if(app_sock < 0)
  51. {
  52. syslog(LOG_ERR, "%s:%d, accept failed", __FILE__, __LINE__);
  53. exit(1);
  54. }
  55. sprintf(sendbuf, "welcome %s:%d here!/n", inet_ntoa(clientaddr.sin_addr.s_addr), clientaddr.sin_port);
  56. //send data
  57. sendlen = strlen(sendbuf) +1;
  58. retlen = 0;
  59. leftlen = sendlen;
  60. ptr = sendbuf;
  61. //while(leftlen)
  62. {
  63. retlen = send(app_sock, ptr, sendlen, 0);
  64. if(retlen < 0)
  65. {
  66. if(errno == EINTR)
  67. retlen = 0;
  68. else
  69. exit(1);
  70. }
  71. leftlen -= retlen;
  72. ptr += retlen;
  73. }
  74. //receive data
  75. recvlen = 0;
  76. retlen = 0;
  77. ptr = recvbuf;
  78. leftlen = RECV_BUF_SIZE -1;
  79. //do
  80. {
  81. retlen = recv(app_sock, ptr, leftlen, 0) ;
  82. if(retlen < 0)
  83. {
  84. if(errno == EINTR)
  85. retlen = 0;
  86. else
  87. exit(1);
  88. }
  89. recvlen += retlen;
  90. leftlen -= retlen;
  91. ptr += retlen;
  92. }
  93. //while(recvlen && leftlen);
  94. printf("receive data is : %s", recvbuf);
  95. close(app_sock);
  96. }
  97. close(listen_sock);
  98. return 0;
  99. }

客户端代码为:

[cpp] view plaincopy

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <syslog.h>
  6. #include <errno.h>
  7. #include <stdlib.h>
  8. #define MAX_LISTEN_NUM 5
  9. #define SEND_BUF_SIZE 100
  10. #define RECV_BUF_SIZE 100
  11. #define SERVER_PORT 1010
  12. int main()
  13. {
  14. int sock_fd = 0;
  15. char recvbuf[RECV_BUF_SIZE] = {0};
  16. char sendbuf[SEND_BUF_SIZE] = {0};
  17. int recvlen = 0;
  18. int retlen = 0;
  19. int sendlen = 0;
  20. int leftlen = 0;
  21. char *ptr = NULL;
  22. struct sockaddr_in ser_addr;
  23. memset(&ser_addr, 0, sizeof(ser_addr));
  24. ser_addr.sin_family = AF_INET;
  25. inet_aton("127.0.0.1", (struct in_addr *)&ser_addr.sin_addr);
  26. ser_addr.sin_port = htons(SERVER_PORT);
  27. sock_fd = socket(AF_INET, SOCK_STREAM, 0);
  28. if(sock_fd < 0)
  29. {
  30. syslog(LOG_ERR, "%s:%d, create socket failed", __FILE__, __LINE__);
  31. exit(1);
  32. }
  33. if(connect(sock_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr)) < 0)
  34. {
  35. syslog(LOG_ERR, "%s:%d, connect socket failed", __FILE__, __LINE__);
  36. exit(1);
  37. }
  38. //receive data
  39. recvlen = 0;
  40. retlen = 0;
  41. ptr = recvbuf;
  42. leftlen = RECV_BUF_SIZE -1;
  43. //do
  44. {
  45. retlen = recv(sock_fd, ptr, leftlen, 0) ;
  46. if(retlen < 0)
  47. {
  48. if(errno == EINTR)
  49. retlen = 0;
  50. else
  51. exit(1);
  52. }
  53. recvlen += retlen;
  54. leftlen -= retlen;
  55. ptr += retlen;
  56. }
  57. //while(recvlen && leftlen);
  58. printf("receive data is : %s", recvbuf);
  59. sprintf(sendbuf, "hello server/n");
  60. //send data
  61. sendlen = strlen(sendbuf) +1;
  62. retlen = 0;
  63. leftlen = sendlen;
  64. ptr = sendbuf;
  65. // while(leftlen)
  66. {
  67. retlen = send(sock_fd, ptr, sendlen, 0);
  68. if(retlen < 0)
  69. {
  70. if(errno == EINTR)
  71. retlen = 0;
  72. else
  73. exit(1);
  74. }
  75. leftlen -= retlen;
  76. ptr += retlen;
  77. }
  78. close(sock_fd);
  79. }

现在一个简单的使用tcp的socket通信的例子已经完成了,这里有几个需要说明的问题

1)头文件:

sys/socket.h   包含了socket相关的函数,如socket,send 和recv, 以及struct sockaddr等

netinet/in.h    包含了地址结构,如struct sockaddr_in

errno.h           包含了errno 和 EINTR

syslog.h         包含了syslog相关的信息,其打印结果在/var/log/messages里面

2)socket地址

对于IPv4来说,其地址用的是struct sockaddr_in,具体结构如下

[cpp] view plaincopy

  1. struct in_addr {
  2. in_addr_t   s_addr;           /* 32-bit IPv4 address */
  3. /* network byte ordered */
  4. };
  5. struct sockaddr_in {
  6. uint8_t         sin_len;      /* length of structure (16) */
  7. sa_family_t     sin_family;   /* AF_INET */
  8. in_port_t       sin_port;     /* 16-bit TCP or UDP port number */
  9. /* network byte ordered */
  10. struct in_addr  sin_addr;     /* 32-bit IPv4 address */
  11. /* network byte ordered */
  12. char            sin_zero[8];  /* unused */
  13. };

其中sin_len我们一般不关注,也不填(只有在使用routing socket的时候才用到,被内核用来处理各种协议簇的地址结构)。
bind, connect, sendto, 和 sendmsg会把socket地址从程序传递给内核; 而accept, recvfrom, recvmsg, getpeername, 和 getsockname会把地址从内核传递给程序。因为不同协议簇的地址结构是不一样的,所以必须要有一个通用的指针来传递地址,对于ANSI C来说我们一般使用void *,但是socket产生早于ANSI C,所以也就没有使用这个机制,而是使用一个通用的地址结构struct sockaddr来处理的

[cpp] view plaincopy

  1. struct sockaddr {
  2. uint8_t      sa_len;
  3. sa_family_t  sa_family;    /* address family: AF_xxx value */
  4. char         sa_data[14];  /* protocol-specific address */
  5. };

IPv6的socket地址为struct sockaddr_in6

[cpp] view plaincopy

  1. struct in6_addr {
  2. uint8_t  s6_addr[16];          /* 128-bit IPv6 address */
  3. /* network byte ordered */
  4. };
  5. #define SIN6_LEN      /* required for compile-time tests */
  6. struct sockaddr_in6 {
  7. uint8_t         sin6_len;      /* length of this struct (28) */
  8. sa_family_t     sin6_family;   /* AF_INET6 */
  9. in_port_t       sin6_port;     /* transport layer port# */
  10. /* network byte ordered */
  11. uint32_t        sin6_flowinfo; /* flow information, undefined */
  12. struct in6_addr sin6_addr;     /* IPv6 address */
  13. /* network byte ordered */
  14. uint32_t        sin6_scope_id; /* set of interfaces for a scope */
  15. };

对于sockaddr-in6来说,我们不能用通用的地址struct sockaddr来存储了,而是产用新的通用地址结构struct sockaddr_storage,这个结构足够大可以存储任何系统支持的地址。

[cpp] view plaincopy

  1. struct sockaddr_storage {
  2. uint8_t      ss_len;       /* length of this struct (implementation dependent) */
  3. sa_family_t  ss_family;    /* address family: AF_xxx value */
  4. /* implementation-dependent elements to provide:
  5. * a) alignment sufficient to fulfill the alignment requirements of
  6. *    all socket address types that the system support
  7. * b) enough storage to hold any type of socket address that the
  8. *    system supports.
  9. */
  10. };
几种常见的地址结构

3) 相关函数的的length
对于从程序传地址给内核的函数(如connect),其长度是一个整型值,告诉内核要copy的地址长度。
对于从内核传递给程序的函数(如accpt),其长度是一个整型指针,是一个value-result参数。有两个目的:一告诉内核地址结构的长度,让内核在copy的时候不要超过这个长度;二返回内核真正copy的长度。

4)字节序
socket相关的函数都是使用网络字节序

5)地址转换函数
inet_aton, inet_ntoa, and inet_addr把IPv4字符串地址转为32位的网络字节序地址
inet_ptonand inet_ntop可以转换IPv4和IPv6的地址

6)listen中的backlog
要知道这个值的含义先用说一下,对于一个listen的socket,有两个队列:一个是incomplete connection队列(仅仅收到SYN);一个是complete connection队列(三次握手完成)。accept函数就是在complete connection队列中取一个socket。backlog就是指队列的个数,但不行的是各个地方都没有明确定义这个值,没有说明究竟代表了哪个队列,或是两个队列之和。一般来说可以
同时处理的连接数是backlog的1.5倍,很多地方都用5.

7) getsockname 和 getpeername
这两个函数可以与socket关联的地址,getsockname 和 getpeername分别得到自己和对端的地址

[cpp] view plaincopy

  1. int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen)
  2. int getpeername(int sockfd , struct sockaddr * peeraddr , socklen_t * addrlen );
时间: 2024-07-30 10:08:00

socket编程——一个简单的例子(转)的相关文章

socket编程——一个简单的例子

从一个简单的使用TCP例子开始socket编程,其基本步骤如下: server                                                  client +++++++                                          ++++++++ 创建socket                                          创建socket +++++++                              

socket编程——一个简单的样例

从一个简单的使用TCP样例開始socket编程,其基本过程例如以下: server                                                  client +++++++                                          ++++++++ 创建socket                                          创建socket +++++++                            

socket计划——一个简单的例子

从一个简单易用TCP样品开始socket计划,的基本过程例如下列: server                                                  client +++++++                                          ++++++++ 创建socket                                          创建socket +++++++                             

socket编程---一个简单例子

服务器端代码(多线程): import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class MultiEchoServer { private static ServerSocket serverSocket; private static final int POR

[转] 3个学习Socket编程的简单例子:TCP Server/Client, Select

以前都是采用ACE的编写网络应用,最近由于工作需要,需要直接只用socket接口编写CS的代码,重新学习这方面的知识,给出自己所用到的3个简单例子,都是拷贝别人的程序.如果你能完全理解这3个例子,估计socket编程就已经基本入门了. 建议:1) 多多查查所用到的网络接口; 2) 最好有一本书,如UNIX环境高级编程,UNIX网络编程,可查询:3) 可以直接使用书上的例子更好. http://blog.csdn.net/zhenjing/article/details/4770490 TCP C

Swift和C混合Socket编程实现简单的ping命令

这个是用Mac下的Network Utility工具实现ping命令,用Wireshark抓取的ICMP数据包: 发送ICMP数据包内容 接受ICMP数据包内容 一.icmp结构 要真正了解ping命令实现原理,就要了解ping命令所使用到的TCP/IP协议.ICMP(Internet Control Message,网际控制报文协议)是为网关和目标主机而提供的一种差错控制机制,使它们在遇到差错时能把错误报告给报文源发方.ICMP协议是IP层的 一个协议,但是由于差错报告在发送给报文源发方时可能

【Python】一个简单的例子

问题描述: Python基础篇 参考资料: (1)http://www.cnblogs.com/octobershiner/archive/2012/12/04/2801670.html (2)http://www.cnblogs.com/itech/archive/2010/06/20/1760345.html 例子: 求解Fibonacci glb_var.py gl_count=1 path.py # coding:utf-8 ''' Created on 2014-4-28 @autho

socket编程,简单多线程服务端测试程序

socket编程,简单多线程服务端测试程序 前些天重温了MSDN关于socket编程的WSAStartup.WSACleanup.socket.closesocket.bind.listen.accept.recv.send等函数的介绍,今天写了一个CUI界面的测试程序(依赖MFC)作为补充.程序功能简介如下: 1:一个线程做监听用. 2:监听线程收到客户端连接后,创建新线程接收客户端数据.所有对客户端线程将加入容器,以便管理. 3:服务端打印所有客户端发来的信息. 4:服务端CUI界面输入数字

Linux下socket编程,附带tcp例子

1.网络中进程之间如何通信? 本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用(Solaris门和Sun RPC) 但这些都不是本文的主题!我们要讨论的是网络中进程之间如何通信?首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们解决了这个问