网络学习六

基本的套接字编程

socket函数

 #include<sys/socket.h>
 int socket(int family, int type, int protocol);
//返回:若成功则为非负描述符,若出错则为-1

其中family是协议族,type是套接字类型,protocol为某个协议组合,设为0的话是取family和type组合的系统默认值。
常用的family值有:AF_INET(IPV4)、AF_INET6(IPV6)。
常用的type值有:SOCK_STREAM(TCP|SCTP)、SOCK_DGRAM(UDP)、SOCK_SEQPACKET(SCTP)。
protocol 若设置为0,以选择所给定family和type组合的系统默认值

connect函数

#include<sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);

sockfd是由socket函数返回的套接字描述符,第二个,第三个参数分别是一个指向套接字地址结构的指针和该结构的大小,
客户端调用connect前不必非得调用bind。如果是TCP套接字,connect会在三路握手建立成功或出错时才返回,出错返回可能是:

  1. *TCP*客户没收到*SYN*分节,返回超时错误。
    
  2. 服务器端的响应为*RST*,表明该服务器没有进程在监听此端口。产生*RST*的三个条件:*SYN*到达的端口没有监听进程;*TCP*想取消一个已有连接;*TCP*接到不存在的连接上的分节。
    
  3. 客户发出的*SYN*被路由认为不可到达。客户内核会重发,若超时后未成功则返回错误。
    

connect导致套接字状态从CLOSED转移到SYN_SENT,若成功再转移到ESTABLISHED,若失败则该套接字不再可用,必须关闭。这样的套接字不可再connect,需要close后重新调用socket获取。

bind函数

#include<sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);

第二个参数是一个指向特定于协议的地址结构的指针,第三个参数是该地址结构的长度
bind是将本地协议地址绑定到套接字上。绑定时未指定的IP地址和端口会由内核选择。
TCP客户通常不绑定,在connect时,内核选择源IP地址。TCP服务器如果没有绑定IP地址,内核将在建立连接时把客户发送的SYN的目的IP设为服务器的源IP地址。
IPV4的通配地址为INADDR_ANY,IPV6的通配地址为IN6ADDR_ANY_INIT。
没有指定bind的端口号时,需要用getsockname来返回协议地址,再获取端口号。
进程捆绑非通配IP到套接字上的常见例子是同一主机上提供多个Web服务器,每个服务器的副本捆绑不同的IP。另一种方法是单个服务器进程绑定通配地址,当客户连接到达时,用getsockname获取客户的目的IP,再处理相应的服务请求。

listen函数

#include<sys/socket.h>
int listen(int sockfd, int backlog);

仅由TCP服务器调用:

  1. socket创建的套接字为主动套接字,listen时会转换成被动套接字,从CLOSED转换为LISTEN。
    
  2. 第二个参数backlog规定了内核应该为相应套接字排队的最大连接个数。
    

内核要为监听套接字维护两个队列:

  1. 未完成连接队列,客户的SYN已到达服务器,未完成三路握手,处于SYN_RCVD状态。
    
  2. 已完成连接队列,完成握手的连接,处于ESTABLISHED状态,等待被accept。
    

不要把backlog设为0。

accept函数

#include<sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

第二个参数是客户端对应的structaddr_in 的结构,第三个就是该结构的大小,通过这个函数我们
如果传了可以获得客户端的structaddr_in 的具体内容
服务器用accept从已完成连接队列头返回下一个已完成连接。
用clientaddr的sin_addr和sin_port字段查看客户的IP和端口。

fork和exec函数

 #include<unistd.h>
pid_t fork(void);

unixfork是派生新进程的唯一方法
fork调用一次返回两次,在他的调用进程中返回一次,返回值是新派生进程的进程id,在子进程又返回一次,返回值为0,因此返回值本身告知当前进程是子进程还是父进程, fork在子进程返回0而不是父进程的进程ID的原因在于:任何子进程只有一个父进程,而且子进程总是可以通过getppid取得父进程的进程id。相反,父进程可以有许多子进程,而且无法获得各个子进程的进程ID,如果父进程想要跟踪子进程的进程ID,那么他必须记录每次调用fork的返回值。
fork有两个典型用法:
1、一个进程创建一个自身的副本,这样每个副本都可以在另一个副本执行其他任务的同时处理各自的某个操作。这是网络服务器的典型用法。我们将在本书后面看到许多这样的例子。
2、一个进程想要执行另一个进程。既然创建新进程的唯一办法是fork,该进程于是首先调用fork创建一个自身的副本,然后其中一个副本调用exec吧自身替换成新的程序。

并发服务器

pid_t pid;
int listenfd, connfd
listenfd = Socket(...);
Bind(listenfd,...);
Listen(listenfd, LISTENQ);
for( ; ; ) {
      connfd = Accept(listenfd, ...);
      if ( (  pid =Fork() ) == 0) {
          Close(lisenfd);
          doit(connfd);
          Close(connfd);
          exit(0);
      }
}

多进程的并发服务器,监听进程在fork后要关掉connfd,子进程在fork后要关掉listenfd,否则描述符的引用计数不为0,在close时不会真正关闭。在fork后listen和connfd的引用计数都都+1了,子进程进入那个if语句块,主进程则不进入。然后我们那个这个连接套接字就可以对连接的这个做一些事了。

close 函数

#include<unistd.h>
int close(int sockfd);

close后的套接字描述符不能再使用,但TCP将尝试发送已排队的任何数据,完毕后进行正常的终止序列。

#include<sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);

前者返回套接字的本地端的地址结构,后者返回外地端的地址结构。只知道connfd的时候,获取客户身份的唯一途径就是调用getpeername。
exec后的程序获取connfd的方法:

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

推荐阅读更多精彩内容