socket
基
本
流
程
socket()
intsocket(intdomain,inttype,intprotocol);
创
建
一个
socket
并
返
回
其
描
述
符
,
该
描
述
符
和
文
件
描
述
符
没
什么
区
别
。
如
果
我
们
的
进
程
没
有
open
其
它
文
件
的
话
,
那
么
调
用
该
函
数
应
该
会
返
回
3
形
参
domain
协
议
族
或
者
是
协
议
域
,
通
常
来
说
会
有
3
个
选
择
AF_UNIX Unix
域
协
议
AF_INET IPv4
协
议
AF_INET6 IPv6
协
议
通
常
来
说
AF_INET
使
用
更
多
type socket
类
型
,
也
就
是
我
们
熟
知的
TCP
协
议
、
UDP
协
议
SOCK_STREAM
流
式
数据
协
议
,
即
TCP
SOCK_DGRAM
数据
报
数据
协
议
,
即
UDP
protocol
通
常
为
0
,
表
示
由
内
核
决
定
最
合
适
的
protocol
值
,
当
然
这通
常
与
前
两个
参
数
有
关
Example intlistenfd=socket(AF_INET,SOCK_STREAM,0);
bind()
intbind(intsockfd,conststructsockaddr*addr,socketlen_taddrlen); bind()
系统
调
用
将
创
建
的
socket
绑
定
到
一个
地址
和
一个
端
口
上
形
参
sockfd socket()
返
回
的
套
接
字
描
述
符
addr
指
向
socket
地址
结
构
的
一个
指
针
,
要
么
是
IPv4
地址
,
要
么
是
IPv6
地址
structsockaddr{
sa_family_tsin_family;
charsa_data[14];
};
sockaddr
有
一个
比
较
蛋
疼
的
问题
就
是
把
IP
和
Port
混
在
了
一
起
,
所
以
大
部
分
情
况
下
会使
用
sockaddr_in
sockaddr_in
structsockaddr_in{
sa_family_tsin_family;
uint16_tsin_port;
structin_addrsin_addr;
charsin_zero[8];
};
structsockaddr_inaddr;
memset(&addr,0,sizeof(addr));//
不
要
使
用
bzero
addr.sin_family=AF_INET;//IPv4
网络
协
议
addr.sin_port=htons(9600);//
将
端
口
转
化
成
网络
字
节
序
addr.sin_addr.s_addr=INADDR_ANY;//
绑
定
本机
任
意
IP
地址
,
通
常
为
0.0.0.0
TIME_WAIT
改
图
是
TCP
连
接
拆
除
时
的
状
态
转
移示
意
图
,
其
它
的
我
们
可
以
不
管
,
主
要
关
注
于
TIME_WAIT
状
态
在
TCP
四
次
挥
手
过
程
中
,
第
一个
FIN
和
最
后
一个
ACK
包
均
由
主
动
断
开
方
发
送
,
并
且,
TIME_WAIT
状
态
也
只
会
出
现
在
主
动
断
开
方
TIME_WAIT
状
态
的
作
用
就
是
为了
确
保
连
接
能
够
被
正
常
的
拆
除
,
因
为
最
后
一个
ACK
包
可
能
会
丢
失
,
那
么
此
时
需
要
主
动
断
开
方
重
传
该
ACK
包
。
并
且,
确
保
老
的
重
复
的
报
文
在
网络
中
过
期
失
效
TIME_WAIT
通
常
会
等
待
2MSL
的
时
间
,
MSL
为
报
文
的
最
大
生
存
时
间
,
Linux
系统
下
默
认
为
60s
,
所
以
TIME_WAIT
默
认
持
续
120s
的
时
间
。
也
就
是
说
,
如
果
server
端
重
启
的
话
,
仍
然
可
能
会
存
在
原
来
的
IP+Port
的
连
接
存
在
,
那
么
重
启后
再
次
进
行
bind
将
失
败
,
会
提
示
addressalreadyinused
SO_REUSEADDR
因
此
,
我
们
创
建
的
socket
在
bind
地址
之
前
,
应
该
为
其
添
加
SO_REUSEADDR
选
项
,
以
重
用
端
口
该
选
项
可
以
告
诉
内
核
,
如
果
当
前
端
口
正
在
被
使
用
,
但
是
TCP
状
态
处
于
TIME_WAIT
的
话
,
允
许
应
用
程
序
重
用
该
端
口
。
但
是
如
果
端
口
正
在
被
使
用
且
TCP
状
态
为
其
它
状
态
时
,
仍
然
返
回
错
误
,
表
明
端
口
已
经
被
使
用
intreuse_addr=1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(constvoid*)&reuse_addr,sizeof(int));
listen()
intlisten(intsockfd,intbacklog); listen()
系统
调
用
将
文
件
描
述
符
sockfd
所
引
用
的
socket
标
记
为
被
动
,
表
示
开
始
监
听
某
一个
端
口
监
听
队
列
这
是
TCP
三
次
握
手
的
示
意
图
。
通
常
而
言
,
都
是
由
客
户
端
主
动
发
起
连
接
当
服
务
端
收
到
了
SYN
包
以
后
,
那
么
连
接
状
态
就
会
由
LISTEN
转
变
为
SYN_RECV
,
这
个
状
态
表
示
服
务
端
三
次
握
手
还
没
有
完
成
,
所
以也
被
称
之为
“
半
连
接
”
只
有
当
再
次
收
到
客
户
端
发
来
的
ACK
确
认
包
以
后
,
该
连
接
才
会
有
SYN_RECV
状
态
转
移
至
ESTABLISHED
状
态
,
表
明
连
接
已完
全
建
立
,
双
方
均
可
收
发
数据
那
么
,
对
于
服
务
端
来
说
,不
管
是
半
连
接
还
是
已
建
立
的
连
接
,
都
需
要
保
存
在
内
存
中
。
内
核
使
用
两个
队
列
来
进
行
存
储
,
分别
为
未
完
成
连
接
队
列
,
和
已完
成
连
接
队
列
当
半
连
接收
到
了
ACK
确
认
包
以
后
,
内
核
将
该
连
接
从
未
完
成
连
接
队
列
移
入
至
已完
成
连
接
队
列
中
在
以
往
,
backlog
参
数
的
含
义
表
示
已完
成
连
接
队
列
大
小
+
未
完
成
连
接
队
列
的
大
小
的
最
大
值
但
是
后
来
改
参
数
得
到
了修
正
,
仅
表
示
已完
成
连
接
队
列
的
最
大
长
度
将
backlog
的
含
义
定
义为
“
已完
成
连
接
队
列
的
最
大
长
度
”
可
以
在
一
定
程
度
上
防
止
SYN
泛洪
攻
击
,
但
是
不
能
从
根本
上
解
决
这
个
问题
accept()
intaccept(intsockfd,structsockaddr*addr,socklen_t*addrlen)
accept()
系统
调
用
将
返
回
一个
全
新
的
socket
文
件
描
述
符
,
用
于
表
示
与
之
通
信
的
具
体
客
户
端
客
户
端
IP
地址
等
信
息
通过
addr
以
及
addrlen
参
数
写入
accept()
的
本
质
就
是
从
已完
成
连
接
队
列
的
头
部
取
出
一个
连
接
返
回
给
应
用
程
序
,
那
么
如
果
已完
成
连
接
队
列
中
没
有
任何
数据
,
并
且
socket
被设
置
为
阻
塞
的
话
,
accept()
调
用
将
一
直
阻
塞
所
以
,
accept()
返
回
一个
新
的
socket
描
述
符
也
就
不
那
么令人
吃
惊
了
。
通过
socket()
系统
调
用
所
创
建
的
socket
描
述
符
主
要
的目的
就
是
为了
监
听
端
口
,
而
通过
accept()
获
得
的
socket
描
述
符
才
是
和
客
户
端
通
信
的
媒
介
accept4()
从
内
核
2.6.28
开
始
,
Linux
内
核
支
持
使
用
非
标
准
系统
调
用
accept4()
来
接收新
的
连
接
,
使
用
该
函
数
可
能
会
有
移
植
性
的
问题
,
程
序
需
要
考
虑
到
这
一
点
intaccept4(intsockfd,structsockaddr*addr,socklen_t*addrlen,intflags)
在
使
用
accept4()
时
,
我
们
可
以
直
接
指
定
SOCK_NONBLOCK
参
数
,
使
得
返
回
的
socket
后
续
操
作为
非阻
塞
,
无
需
再
使
用
fcntl()
设
置
了