Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5096323
  • 博文数量: 921
  • 博客积分: 16037
  • 博客等级: 上将
  • 技术积分: 8469
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 02:08
文章分类

全部博文(921)

文章存档

2020年(1)

2019年(3)

2018年(3)

2017年(6)

2016年(47)

2015年(72)

2014年(25)

2013年(72)

2012年(125)

2011年(182)

2010年(42)

2009年(14)

2008年(85)

2007年(89)

2006年(155)

分类: C/C++

2015-09-14 14:17:13


  1. 基本TCP套接口编程一
  2. 本文出自:http://sunsland.top263.net 作者: (2001-10-22 12:00:00)

  3. 概述
  4. socket() --得到文件描述符!

  5. bind() --我们在哪个端口?

  6. connect() --Hello!

  7. listen() --有人给我打电话吗?

  8. accept() --"Thank you for calling port 3490."

  9. send() 和 recv() --Talk to me,

  10. sendto() 和 recvfrom() --Talk to me, DGRAM-style

  11. close() 和 shutdown() --滚开!

  12. getpeername() --你是谁?

  13. gethostname() --我是谁?

  14. DNS --你说“白宫”,我说 "198.137.240.100"


  15. --------------------------------------------------------------------------------

  16. socket函数
  17. 功能:指定协议类型

  18. 定义:
  19. #include <sys/types.h>
  20. #include <sys/socket.h>
  21. int socket(int family, int type, int protocol);

  22. 返回值

  23. 出错: -1
  24. 成功: 套接口描述字 (socket file descriptor)(套接字)sockfd

  25. socket 函数指定了协议族(IPv4、IPv6或unix)和套接口类型(字节流、数据报或原

  26. 始套接口)。但并没有指定本地协议地址或远程协议地址。

  27. 理解socket

  28. socket使用 Unix 文件描述符 (file descriptor) 和其他程序通讯的方式。

  29. Unix 程序在执行任何形式的 I/O 的时候,程序是在读或者写一个文件描述符。

  30. 一个文件描述符只是一个和打开的文件相关联的整数。

  31. 这个文件可能是一个网络连接,FIFO,管道,终端,磁盘上的文件或者什么其他

  32. 的东西。Unix 中所有的东西是文件!因此,与 Internet 上别的程序通讯的时候,

  33. 要通过文件描述符。利用系统调用 socket()得到网络通讯的文件描述符。他返回

  34. 套接口描述符 (socket descriptor),然后再通过他来调用 send() 和 recv()

  35. 那么为什么不用一般的调用 read() 和 write() 来通过套接口通讯?

  36. 简单的答案是:可以使用一般的函数!

  37. 详细的答案是:使用 send() 和 recv() 让你更好的控制数据传输。


  38. --------------------------------------------------------------------------------

  39. connect 函数
  40. 功能:建立与TCP服务器的连接

  41. 定义:

  42. #include <sys/types.h>
  43. #include <sys/socket.h>

  44. int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

  45. //sockfd 是系统调用 socket() 返回的套接口文件描述符

  46. serv_addr 是保存着目的地端口和 IP 地址的数据结构 struct sockaddr

  47. //addrlen 设置为 sizeof(struct sockaddr)

  48. connect 激发 TCP的三路握手过程

  49. 服务器必须准备好接受外来的连接。

  50. 这通过调用socket,bind和1isten函数来完成,称为被动打开(Passive open)

  51. 客户通过调用connect进行主动打开(active opn)

  52. 这引起客户TCP发送一个SYN分节(表示同步),它告诉服务器客户将在(待建立的)

  53. 连接中发送的数据的初始序列号。

  54. 服务器必须确认客户的SYN,同时自己也得发送一个SYN分节,它含有服务器将在

  55. 同一连接中发送的数据的韧始序列号。服务器以单个分节向客户发送SYN和对客户

  56. SYN的ACK。客户必须确认服务器的SYN。

  57. connect 出错时的返回

  58. 出错原因 :未收到SYN的响应(服务器超时,75s)

  59. 返回值:ETIMEDOUT

  60. 用户端输出:Connection time out.
  61.  
  62. 出错原因 :收到RST响应(Hard error)SYN到达服务器,但该服务器的无此项端口服务

  63. 返回值:ECONNREFUSE

  64. 用户端输出:Connection refused

  65. 出错原因 :ICMP错误:不可路由(soft error)(目的地不可达)

  66. 返回值:EHOSTUNREACH

  67. 用户端输出:ENETUNREACH No route to host


  68. --------------------------------------------------------------------------------

  69. bind 函数
  70. 功能:给套接口分配一个本地协议地址

  71. 定义:

  72. #include <sys/types.h>
  73. #include <sys/socket.h>

  74. int bind(int sockfd, const struct sockaddr *my_addr, int addrlen);

  75. sockfd 是调用 socket 返回的文件描述符。

  76. my_addr 是指向数据结构 struct sockaddr 的指针,保存地址(即端口和 IP 地址) 信息。

  77. addrlen 设置为 sizeof(struct sockaddr)

  78. 返回: 0—成功, -1---出错

  79. 让内核自动处理地址ip和端口port

  80. my_addr.sin_port = 0; /* choose an unused port at random */
  81. my_addr.sin_addr.s_addr = INADDR_ANY; /* use my IP address */

  82. bind( ) 自己选择合适的端口:将0赋给 my_addr.sin_por。

  83. 自动填上他所运行的机器的 IP 地址:my_addr.sin_addr.s_addr 设置为 INADDR_ANY。

  84.  

  85. --------------------------------------------------------------------------------

  86. listen 函数
  87. 功能:将未连接主动套接口的转换为被动套接口,指示内核接受对该套接口的连接请求.

  88. CLOSED --? LISTEN

  89. 定义:

  90. #include <sys/socket.h>

  91. int listen(int sockfd, int backlog);

  92. sockfd 是调用 socket() 返回的套接口文件描述符。

  93. backlog 是在进入队列中允许的连接数目。

  94. 监听套接口的两个队列

  95. 未完成连接队列(incompleted connection queue): SYN_RECV

  96. 已完成连接队列(completed connection queue): ESTABLISHED

  97. 当一个客户的SYN到达时,如两队列都满的, TCP将忽略该分节且不发RST


  98. --------------------------------------------------------------------------------

  99. ACCEPT 函数
  100. 功能:在已完成队列头返回下一个已完成的连接

  101. 定义

  102. #include <sys/socket.h>

  103. int accept(int sockfd, struct sockaddr *cliaddr, int* addrlen);

  104. 调用成功时返回: 1. cliaddr: 客户进程的协议地址和地址大小 2. 新套接口描述字

  105. (已连接套接口描述字)

  106. 监听套接口描述字 listening socket descriptor

  107. 一个给定的服务器常常是只生成一个监听套接口, 且一直存在,直到该服务器关闭。

  108. 已连接套接口描述字connected socket descriptor

  109. 内核为每个被接受的客户连接创建了一个已连接套接口。当服务器完成某客户的服务时,

  110. 关闭已连接套接口。

  111. 1024以下的端口:超级用户使用


  112. --------------------------------------------------------------------------------

  113. fork 函数
  114. 功能:派生新进程 create new process

  115. 定义:
  116. #include <sys/unistd.h>

  117. pid_t fork (void);

  118. 在子进程中返回0,在父进程中返回子进程的进程ID

  119. 出错时返回 –1,调用一次返回两次

  120. fork的典型应用:

  121. 1.一个进程可为自己创建一个拷贝。当一个拷贝处理一个操作时,其他的拷贝可以

  122. 执行其他的任务。这是非常典型的网络服务器。

  123. 2.一个进程想执行其他的程序,由于创建新进程的唯一方法是调用fork,进程首先

  124. 调 用fork来生成一个拷贝,然后其中一个拷贝(通常为子进程)调用exec 来代替自己

  125. 去执行新程序。


  126. (http://www.fanqiang.com)
  127.  

  128. -----------------------------------------------------------------------------------------------------------------------------

  129. -----------------------------------------------------------------------------------------------------------------------------

  130. 并发服务器

  131. 迭代服务器 iterative server 单进程

  132. 并发服务器 concurrent server 多进程

  133. 当连接建立时,accept返回,服务器调用fork

  134. 子进程为客户提供服务(通过connfd已连接套接口)

  135. 父进程等待另一个连接(通过listenfd监听套接口)

  136. 子进程开始处理新客户后,父进程便关闭已连接套接口。

  137. 每个文件或套接口都有一个访问计数,该访问计数在文件表项中维护,它表示当前指

  138. 向该文件或套接口的打开的描述字个数。

  139. 从sock返回后,与listenfd关联的文件表项访问计数值为1,

  140. 从accept返回后,与connfd关联的文件表项访问计数值也为1。

  141. 当fork返回后,两个描述字在父进程与子进程间共享(duplicated)与两个套接门相关

  142. 联的文件表项访问计数值均为2。

  143. 当父进程关闭connfd时,只是将访问计数值从2减为1。描述字只在访问计数值达到0时

  144. 才真正关闭,这在后面某个时候子进程关闭connfd时会碰上.

  145.  

  146. --------------------------------------------------------------------------------

  147. close 函数
  148. 功能:将套接口做上“已关闭的标记”,并立即返回进程。

  149. 将套接口描述字的访问计数器减1。

  150. 当访问计数器值为0时,引发TCP的四个分组连接终止序列,从而关闭套接口。

  151. 定义:
  152. #include <sys/unistd.h>
  153. int close(int sockfd);

  154.  

  155. --------------------------------------------------------------------------------

  156. getsockname 和 getpeername函数
  157. 功能:

  158. getsockname: 返回本地协议地址

  159. getpeername:返回远程协议地址

  160. 定义:

  161. #include <sys/unistd.h>

  162. int getsockname (int sockfd, struct sockaddr *localaddr, int *addrlen);
  163. int getpeername(int sockfd, struct sockaddr *peeraddr, int *addrlen);


  164. --------------------------------------------------------------------------------

  165. 一个示例程序:
  166. #include <string.h>
  167. #include <sys/types.h>
  168. #include <sys/socket.h>
  169. #define MYPORT 3490 /* the port users will be connecting to */
  170. #define BACKLOG 10 /* how many pending connections queue will hold */
  171. main()
  172. {
  173. int sockfd, new_fd; /* listen on sock_fd, new connection on new_fd */
  174. struct sockaddr_in my_addr; /* my address information */
  175. struct sockaddr_in their_addr; /* connector's address information */
  176. int sin_size;
  177. sockfd = socket(AF_INET, SOCK_STREAM, 0); /* do some error */
  178. my_addr.sin_family = AF_INET; /* host byte order */
  179. my_addr.sin_port = htons(MYPORT); /* short, network byte order */
  180. my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
  181. bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */
  182. /* don't forget your error checking for these calls: */
  183. bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
  184. listen(sockfd, BACKLOG);
  185. sin_size = sizeof(struct sockaddr_in);
  186. new_fd = accept(sockfd, &their_addr, &sin_size);
  187. . . . . . . . . . . . . .

阅读(2602) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~