编写一个完整的TCP客户和服务器程序所需要的基本套接口函数

1、socket函数(客户端、服务器端都必须调用)

参数family指明协议族(family),该参数也往往被称为协议域(domain)。所以有的书上声明如下:

而且对于socket函数第一个参数,在不同书籍上可能会看到不同前缀的取值常量列表,如下两图所示:

AF_xxx与PF_xxx:

AF_前缀表地址族,PF_前缀表示协议族。历史上曾有这样的想法:单个协议族可以支持多个地址族,PF_值用来创建套接口,而AF_值用于套接口地址结构。但实际上,支持多个地址族的协议族从来就未实现过,而且头文件<sys/socket.h>中为一给定协议定义的PF_值总是与此协议的AF_值相等

2、connect函数(TCP客户端调用)

客户在调用函数connect前不必非得调用bind函数,因为如果需要的话,内核会确定源IP地址,并选择一个临时端口作为源端口。

如果是TCP套接口,调用connect函数将激发TCP的三路握手过程,而且仅在连接建立成功或出错时才返回,其中出错返回可能有以下几种情况:

(1)若TCP客户没有收到SYN分节的响应,则返回ETIMEDOUT错误。

(2)若对客户的SYN的响应是RST(表示复位),则表明该服务器主机在我们指定的端口上没有进程在等待与之连接(例如服务器进程也许没在运行)。这是一种硬错误(hard error),客户一接收到RST就马上返回ECONNREFUSED错误。

(3)若客户发出的SYN在中间的某个路由器上引发了一个“destination unreachable”(目的地不可达)ICMP错误,则认为是一种软错(soft error)。客户主机内核保存该消息,并按一定时间间隔延迟重发SYN。若在某个规定的时间(4.4BSD规定为75秒)后仍未收到响应,则 把保存的消息(即ICMP错误)作为EHOSTUNREACH或ENETUNREACH错误返回给进程。

若connect失败则该套接口不再可用,必须关闭,我们不能对这样的套接口再次调用connect函数。当循环调用函数connect尝试给定主机的各个IP地址直到有一个成功时,每次connect失败后,都必须close当前的套接口描述字,重新调用socket。

3、bind函数(服务器调用、客户端可以调用也可不调用)

进程可以把一个特定的IP地址捆绑到它的套接口上,不过这个IP地址必须属于其所在主机的网络接口之一。对于TCP客户,这就为在该套接口上发送的IP数据报指派了源IP地址。对于TCP服务器,这就限定该套接口只接收那些目的地为这个IP地址的客户连接。

TCP客户通常不把IP地址捆绑到它的套接口上。当连接套接口时,内核将根据所用外出网络接口来选择源IP地址,而所用外出接口则取决于到达服务器所需的路径。

如果指定端口号为0,那么内核就在bind被调用时选择一个临时端口;

如果指定IP地址为通配地址,那么内核将等到套接口已连接(TCP)或已在套接口上发出数据报(UDP)时才选择一个本地IP地址。

对于IPv4来说,通配地址由常值INADDR_ANY来指定,其值一般为0. 它告知内核去选择IP地址。

无论是网络字节序还是主机字节序,INADDR_ANY的值(为0)都一样,因此使用htonl并非必须。不过既然头文件<netinet/in.h>中定义的所有INADDR_常值都是按照主机字节序定义的,我们应该对所有这些常值都使用htonl。

4、listen函数(TCP服务器调用)

listen函数做两件事情:

(1)当socket函数创建一个套接口时,它被假设为一个主动套接口,也就是说,它是一个将调用connect发起连接的客户套接口。listen函数把一个未连接的套接口转换成一个被动套接口,指示内核应该接受指向该套接口的连接请求。调用listen导致套接口从CLOSED状态转换到LISTEN状态。

(2)backlog参数规定了内核应该为相应套接口排队的最大连接个数。

为了理解其中的backlog参数,我们必须认识到内核为任何一个给定的监听套接口维护两个队列:

(1)未完成连接队列(incomplete connection queue),每个这样的SYN分节对应其中一项:已由客户发出并到达服务器,而服务器正在等待完成相应的TCP三路握手过程。这些套接口处于SYN_RCVD状态。

(2)已完成连接队列(completed connection queue),每个已完成TCP三路握手过程的客户对应其中一项。这些套接口处于ESTABLISHED状态。

当进程调用accept时,已完成连接队列中的队头项将返回给进程,或者如果该队列为空,那么进程将被投入睡眠,直到TCP在该队列中放入一项才唤醒它。

不要把backlog定义为0,因为不同的实现对此有不同的解释。如果不想让客户连接到你的监听套接口上,那就关掉该监听套接口。

5、accept函数(TCP服务器调用)

accept函数由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接。如果已完成连接队列为空,那么进程被投入睡眠(假定套接口为缺省的阻塞方式)。

参数cliaddr和addrlen用来返回已连接的对端进程(客户)的协议地址。

如果accept成功,那么其返回值是由内核自动生成的一个全新描述字,代表与所返回客户的TCP连接。

在讨论accept函数时,我们称它的第一个参数为监听套接口(listening socket)描述字(由socket创建,随后用作bind和listen的第一个参数的描述字),称它的返回值为已连接套接口(connected socket)描述字。区分这两个套接口非常重要。一个服务器通常仅仅创建一个监听套接口,它在服务器的生命期内一直存在。内核为每个由服务器进程接受的客户连接创建一个已连接套接口(也就是说对于它的TCP三路握手过程已经完成)。当服务器完成对于某个给定客户的服务时,相应的已连接套接口就被关闭。

本函数最多返回三个值:一个既可能是新套接口描述字也可能是出错指示的整数、客户进程的协议地址(由cliaddr指针所指)以及该地址的大小(由addrlen指针所指)。如果我们对返回客户协议地址不感兴趣,那么可以把cliaddr和addrlen均设置为空指针。

6、fork和exec函数(构建并发服务器)

fork函数:http://www.cnblogs.com/nufangrensheng/p/3509492.html

exec函数:http://www.cnblogs.com/nufangrensheng/p/3510821.html

7、close函数

UNIX通常的close函数也用来关闭套接口,并终止TCP连接。

close一个TCP套接口的缺省行为是把该套接口标记成已关闭,然后立即返回到调用进程。该套接口描述字不能再由调用进程使用,也就是说它不能再作为read或write的第一个参数。然而TCP将尝试发送已排队等待发送到对端的任何数据,发送完毕后发生的是正常的TCP连接终止序列。

8、getsockname和getpeername函数

getsockname:返回与某个套接口关联的本地协议地址。

getpeername:返回与某个套接口关联的远地协议地址。

这两个函数返回与某个网络连接的两端中任何一端相关联的协议地址,对于IPv4和IPv6来说,就是IP地址和端口号的组合。

需要这两个函数的理由如下:

(1)在没有调用bind的TCP客户上,connect成功返回后,getsockname用于返回由内核赋予该连接的本地IP地址和本地端口号。

(2)在以端口号0调用bind(告知内核去选择本地端口号)后,getsockname用于返回由内核赋予的本地端口号。

(3)getsockname可用于获取某个套接口的地址族。

(4)在一个以通配IP地址调用bind之后的TCP服务器上,与某个客户的连接一旦建立(accept成功返回),getsockname就可以用于返回由内核赋予该连接的本地IP地址。在这样的调用中,套接口描述字必须是已连接套接口的描述字,而不是监听套接口的描述字。

(5)当一个服务器是由调用过accept的某个进程通过调用exec更换了程序时,它能够获取客户身份的唯一途径便是调用getpeername。

总结:

所有客户和服务器都从调用socket开始,它返回一个套接口描述字。客户随后调用connect,服务器则调用bind、listen和accept。套接口通常使用标准的close函数关闭。

UNIX网络编程读书笔记:基本TCP套接口编程的更多相关文章

  1. UNIX网络编程读书笔记:原始套接口

    概述 应用程序可以绕过传输层而直接使用IPv4和IPv6,这称为原始套接口(raw socket).http://www.cnblogs.com/nufangrensheng/p/3583435.ht ...

  2. 值得收藏的TCP套接口编程文章

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由jackieluo发表于云+社区专栏 TCP客户端-服务器典型事件 下图是TCP客户端与服务器之间交互的一系列典型事件时间表: 首先启 ...

  3. Linux C 网络编程——3. TCP套接口编程

    1. 基本流程 2. socket() int socket(int domain, int type, int protocol); socket()打开一个网络通讯端口,如果成功的话,就像open ...

  4. 【转】Linux C 网络编程——TCP套接口编程

    地址:http://blog.csdn.net/matrix_laboratory/article/details/13669211 2. socket() <span style=" ...

  5. Unix 网络编程 读书笔记3

    第四章 基本tcp 套接口编程 注意区分AF_XXX 和PF_XXX,AF代表address family, PF代表protocol family. 1 socket 函数 2 connect 函数 ...

  6. UNIX网络编程读书笔记:套接口选项

    概述 有很多方法来获取和设置影响套接口的选项: getsockopt和setsockopt函数 fcntl函数 ioctl函数 getsockopt和setsockopt函数 这两个函数仅用于套接口. ...

  7. UNIX网络编程读书笔记:基本SCTP套接口编程

    概述 SCTP是一个较新的传输协议,于2000年在IETF得到标准化(TCP是在1981年标准化的).它最初是为满足不断增长的IP电话市场设计的:具体地说,就是穿越因特网传输电话信令. SCTP是一个 ...

  8. UNIX网络编程读书笔记:基本UDP套接口编程

    概述 使用UDP编写的一些流行的应用程序有:DNS(域名系统).NFS(网络文件系统)和SNMP(简单网络管理协议). 如下图所示,给出了典型的UDP客户/服务器程序的函数调用: 客户不与服务器建立连 ...

  9. UNIX网络编程读书笔记:端口号、套接口对和套接口

    端口号 端口号(port number):16位整数,用来区分不同的进程. 服务器使用的端口号:TCP和UDP定义了一组众所周知的端口(well-known port),用于标识众所周知的服务. 客户 ...

随机推荐

  1. BZOJ4530 BJOI 2014 大融合

    对LCT子树大小进行维护. size表示实子树大小,sz表示虚子树大小. 具体操作是体现在link和splay中,可以看代码. 注意每次做完都要update. By:大奕哥 #include<b ...

  2. ZOJ 3707 Calculate Prime S 数论

    思路:容易得到s[n]=s[n-1]+s[n-2],也就是fib数. 求第k小的fib质数的也就是第k个质数数-2,当k>2时. 在就是s[n]/x%m=s[n]%(x*m)/x. 代码如下: ...

  3. bzoj 1779

    较水的网络流. /************************************************************** Problem: 1779 User: idy002 L ...

  4. 今天测试了一下 sqlalchemy 性能

    self.db.query(Users).filter(Users.Id==1).first() < self.db.execute('SELECT *  FROM `users` WHERE ...

  5. .net程序保护方式大观

    .net软件保护方式大观 最近调试一个运行于.net 2.0下的软件,发现该软件使用的保护方式很具有代表性,基本囊括了现在.net下的所有保护措施.实践证明,这些保护措施就像全真七子,单打独斗功力差了 ...

  6. android开发:退出程序(对话框、两次返回键退出)

    private void exitDialog() { AlertDialog.Builder aa=new AlertDialog.Builder(this); aa.setTitle(" ...

  7. Java垃圾回收精粹 — Part3

    Java垃圾回收精粹分4个部分,本篇是第3部分.在第3部分里介绍了串行收集器.并行收集器以及并发标记清理收集器(CMS). 串行收集器(Serial Collector) 串行收集器是最简单的收集器, ...

  8. SWT常用组件

    SWT类所代表的事件常量: 事件类型常量 说明 SWT.Activate 当激活窗口时 SWT.Arm 菜单项被选中之前 SWT.Close 关闭窗口时 SWT.Collapse 折叠树的节点时 SW ...

  9. Object 转换为 BigDecimal

    项目中遇到读取Excel文件里面的数据转为金额的情况,为了程序更加的健壮,进行处理如下: import java.math.BigDecimal; import java.math.BigIntege ...

  10. 6)Linux程序设计入门--消息管理

    )Linux程序设计入门--消息管理 前言:Linux下的进程通信(IPC) Linux下的进程通信(IPC) POSIX无名信号量 System V信号量 System V消息队列 System V ...