Unix网络编程-基本TCP套接字编程(1)

本文讲解编写一个完整的TCP客户/服务器程序所需要的基本套接字函数。

socket函数

为了执行网络I/O,一个进程必须做的第一件事情就是调用socket函数,指定期望的通信协议类型(TCP、UDP、Unix域等)

#include

int  socket(int  family, int  type, int  protocol);

                            返回:若成功则为非负描述符,若出错则为-1

参数family指明协议族,他的取值如下图所示:

参数type指明套接字类型,他的取值如下所示:

参数protocol 指定为某个具体的协议类型常值,或者指定为0,根据给定的family和type组合,系统选择默认的值。

参数family 和 type 的有效组合如下图所示:

socket函数在成功时返回一个小的非负整数值,他与文件描述符类似,我们把他称为套接字描述符。

connect函数

Tcp客户端用connect函数来建立与TCP服务器的连接。

#include <sys/socket.h>

int  connect (int  sockfd , const  struct  sockaddr*  servaddr,  socklen_t  addrlen);

                                                            返回:若成功则为0, 若出错则为-1

sockfd是由socket函数返回的套接字描述符,第二个、第三个参数分别是一个指向套接字地址结构的指针和结构体大小,套接字地址结构必须含有服务器的IP地址和端口号。如果是TCP套接字,调用connect函数将激发TCP的三路握手过程,而且仅在连接建立成功或者出错时才返回,其中出错返回可能有以下几种情况。

1) 若TCP客户端没有收到SYN分节的响应,则返回ETIMEDOUT错误。举例来说,调用connect函数时,4.4BSD内核发送一个SYN,若无响应则等待6s后再发送一个,若仍无响应则等待24s后再发送一个,若总共等了75s后仍没有收到响应则返回该错误。

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

产生RST的三个条件:a) 目的地为某端口的SYN到达,但是该端口上没有正在监听的服务器进程。b)  TCP想取消一个已有连接。c)  TCP收到一个根本不存在的连接上的分节。

3) 若客户发出的SYN在中间的某个路由器上引发一个destination  unreachable 目的地不可达的ICMP错误,则认为是一种软错误(soft  error)。客户主机内核保存该消息,并按第一种情况种所述的时间间隔连续发送SYN。若在某个规定的时间后仍未收到响应,则把保存的消息作为EHOSTUNREACH或者ENETUNREACH错误给进程。

按照TCP状态转换图,connect函数导致当前套接字从CLOSED状态(该套接字自从由sockect函数创建以来一直所处的状态)转移到SYN_SENT状态,若成功则转移到ESTABLISHED状态。若connect失败则该套接字不再可用,必须关闭,我们不能对这样的套接字再次调用connect函数。即每次connect失败后,都必须调用close函数关闭。

bind函数

bind函数把一个本地协议地址赋予一个套接字。对于网际协议,协议地址是32位的IPV4地址或者128位的IPV6地址与16位的TCP或者UDP端口号的组合。

#include<sys/socket.h>

int    bind( int  sockfd, const  struct  sockaddr*  myaddr  ,socklen_t  addrlen);

                        返回:若成功则位0,若出错则位-1

第二个参数是一个指向特定与协议的地址结构的指针,第三个参数是该地址结构的长度。对于TCP,调用bind函数可以指定一个端口号,或指定一个IP地址,也可以两者都指定,还可以都不指定。

a) 服务器在启动时捆绑他们的众所周知端口,如果一个TCP客户或者服务器未蹭调用bind捆绑一个端口,当调用connect或者listen时,内核就要为相应的套接字选择一个临时端口。让内核来选择临时端口对于TCP客户来说时正常的,除非应用需要一个预留端口;然而对于TCP服务器来说却极为罕见,因为服务器是通过他们的众所周知端口被大家认知的。

b) 进程可以把一个特定的IP地址捆绑到他的套接字上,不过这个IP地址必须属于其所在主机的网络接口之一。对于TCP客户端,这就为在该套接字上发送的IP数据报指派了源IP地址。对于TCP服务器,这就限定该套接字只接收那些目的地为这个IP地址的客户连接。TCP客户通常不把IP地址捆绑到他的套接字上。当连接套接字时,内核将根据所用外出网络接口来选择源IP地址,而所用外出接口则取决于到达服务器所需的路径。如果TCP服务器没有把IP地址捆绑到他的套接字上,内核就把客户发送的SYN的目的IP地址作为服务器的源IP地址。

如果指定端口号为0,那么内核就在bind被调用时选择一个临时端口。然后,如果指定IP地址为通配地址,那么内核将等到套接字已连接(TCP)或者已在套接字上发出数据报(UDP)时才选择一个本地IP地址。

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

struct  sockaddr_in    servaddr ;

servaddr.sin_addr.s_addr =htonl(INADDR_ANY);    /* wildcard */

对于IPV6

struct  sockaddr_in6    serv;

serv.sin6_addr = in6addr_any;      /* wildcard */

如果让内核来为套接字选择一个临时端口号,必须调用函数getsockname来返回协议地址。bind函数返回的一个常见的错误时EADDRINUSE。

listen函数

#include<sys/socket.h>

int  listen(int  sockfd , int  backlog);

                      返回:若成功则为0,若出错则为-1。

listen函数仅由TCP服务器调用,他做两件事情。

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

2) 本函数的第二个参数规定了内核应该为相应套接字排队的最大连接个数。

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

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容