本文旨在整理一下linux下socket编程时一些常用的一些理解总结,如有不足希望大家批评指点
Linux version 3.10.0-862.14.4.el7.x86_64
gcc version 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC)
TCP的服务器端socket基本流程socket->bind->listen->accept->send/recv->closesocket
客户端基本流程socket->[bind->]->connect->send/recv->closesocket
一.socket(创建套接字)
首先看socket接口定义
int socket (int domain, int type, int protocol);
输入参数:
domain:地址协议族(一般socket选AF_INET)
/* Address families. */
#define AF_UNSPEC PF_UNSPEC //未指定
#define AF_LOCAL PF_LOCAL // 本地到主机(管道和文件域)。
#define AF_UNIX PF_UNIX //只能用于本机内进程之间的通信
#define AF_FILE PF_FILE //PF_LOCAL的另一个非标准名称
#define AF_INET PF_INET //IP协议 internetwork: UDP, TCP, etc.
#define AF_AX25 PF_AX25 //业余无线电AX.25。
#define AF_IPX PF_IPX //Novell网络协议
......
type:socket类型(TCP:SOCK_STREAM UDP:SOCK_DGRAM)
enum __socket_type
{
SOCK_STREAM = 1, /* 顺序的,可靠的,基于连接的字节流。TCP */
#define SOCK_STREAM SOCK_STREAM
SOCK_DGRAM = 2, /* 固定最大长度的无连接、不可靠的数据报。 UDP */
#define SOCK_DGRAM SOCK_DGRAM
SOCK_RAW = 3, /* 原始协议接口 */
#define SOCK_RAW SOCK_RAW
SOCK_RDM = 4, /* 可靠交付消息。 */
#define SOCK_RDM SOCK_RDM
SOCK_SEQPACKET = 5, /* 顺序的,可靠的,基于连接的,固定最大长度的数据报。 */
#define SOCK_SEQPACKET SOCK_SEQPACKET
SOCK_DCCP = 6, /* 数据报拥塞控制协议。 */
#define SOCK_DCCP SOCK_DCCP
SOCK_PACKET = 10, /Linux特有的在开发级别获取包的方法。用于在用户级编写rarp和其他类似的东西。 */
#define SOCK_PACKET SOCK_PACKET
/* 将标志定位到套接字和socketpair的类型参数中,并用于paccept的标志参数。 */
SOCK_CLOEXEC = 02000000, /* 原子地为新的描述符设置close-on-exec标志。 */
#define SOCK_CLOEXEC SOCK_CLOEXEC
SOCK_NONBLOCK = 00004000 /* 原子标记描述符为非阻塞。 */
#define SOCK_NONBLOCK SOCK_NONBLOCK
};
protocol:指定协议(TCP:IPPROTO_IP UDP:IPPROTO_UDP)
/* Standard well-defined IP protocols. */
enum
{
IPPROTO_IP = 0, /* Dummy protocol for TCP. */
#define IPPROTO_IP IPPROTO_IP
IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */
#define IPPROTO_ICMP IPPROTO_ICMP
IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */
#define IPPROTO_IGMP IPPROTO_IGMP
IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94). */
#define IPPROTO_IPIP IPPROTO_IPIP
IPPROTO_TCP = 6, /* Transmission Control Protocol. */
#define IPPROTO_TCP IPPROTO_TCP
IPPROTO_EGP = 8, /* Exterior Gateway Protocol. */
#define IPPROTO_EGP IPPROTO_EGP
IPPROTO_PUP = 12, /* PUP protocol. */
#define IPPROTO_PUP IPPROTO_PUP
IPPROTO_UDP = 17, /* User Datagram Protocol. */
#define IPPROTO_UDP IPPROTO_UDP
......
}
返回值:
新套接字的文件描述符,或错误返回-1。
二.setsockopt(设置套接字选项)
函数原型:
int setsockopt (int fd, int level, int optname,
const void *optval, socklen_t optlen)
输入参数:
fd:标识一个套接口的描述字。
level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6,如果想要在套接字级别上设置选项,就必须把level设置为 SOL_SOCKET
optname:需设置的选项。option_name可以有哪些取值,这取决于level
SOL_SOCKET可选项:
#define SO_DEBUG 1 //打开或关闭调试信息。当option_value不等于0时,打开调试信息,否则,关闭调试信息
#define SO_REUSEADDR 2 //打开或关闭地址复用功能。当option_value不等于0时,打开,否则,关闭
#define SO_TYPE 3 //套接口选项
#define SO_ERROR 4 //获取错误状态
#define SO_DONTROUTE 5 //打开或关闭路由查找功能。当option_value不等于0时,打开,否则,关闭。
#define SO_BROADCAST 6 //允许套接口传送广播信息
#define SO_SNDBUF 7 //指定发送缓冲区大小
#define SO_RCVBUF 8 //接收确定缓冲区大小
#define SO_SNDBUFFORCE 32 //强制设置发送缓存区大小,可设置不小于2K的任意缓冲区大小
#define SO_RCVBUFFORCE 33 //强制设置接收缓存区大小,可设置不小于2K的任意缓冲区大小
#define SO_KEEPALIVE 9 //套接字保活。如果协议是TCP,并且当前的套接字状态不是侦听(listen)或关闭(close),那么,当option_value不是零时,启用TCP保活定时器,否则关闭保活定时器。
#define SO_OOBINLINE 10 //在常规数据流中接收带外数据
#define SO_NO_CHECK 11 //打开或关闭校验和
#define SO_PRIORITY 12 //设置在套接字发送的所有包的协议定义优先权。Linux通过这一值来排列网络队列。这个值在0到6之间(包括0和6),由option_value指定。
#define SO_LINGER 13 //如果选择此选项, close或 shutdown将等到所有套接字里排队的消息成功发送或到达延迟时间后>才会返回. 否则, 调用将立即返回。
该选项的参数(option_value)是一个linger结构:
struct linger {
int l_onoff;
int l_linger;
};
如果linger.l_onoff值为0(关闭)
#define SO_BSDCOMPAT 14 //BSD兼容
#define SO_REUSEPORT 15 //支持多个进程或者线程绑定到同一端口,提高服务器程序的性能
#ifndef SO_PASSCRED /* powerpc only differs in these */
#define SO_PASSCRED 16 //启用或禁用接收SCM_CREDENTIALS控制消息
#define SO_PEERCRED 17 // 返回连接到此套接字的进程的凭据
#define SO_RCVLOWAT 18 //指定套接层传递数据到用户接收时,缓冲区至少应该有多少字节数
#define SO_SNDLOWAT 19 //指定套接层传递数据到协议时,缓冲区至少应该有多少字节数
#define SO_RCVTIMEO 20 // 指定接收报告错误之前的超时值
#define SO_SNDTIMEO 21 // 指定发送报告错误之前的超时值
#endif
optlen:optval缓冲区长度。
返回值:
成功返回0,错误返回-1
三.bind(绑定)
函数原型:
int bind (int fd, CONST_SOCKADDR_ARG addr, socklen_t len)
输入参数:
fd:标识未捆绑套接口的描述字。
addr:赋予套接口的地址
len:addr的长度。可以用sizeof操作符获得
返回值:
成功返回0,失败返回-1.
四. listen(侦听)
函数原型:
int listen (int fd, int n)
入参数:
fd:套接口的描述字。
n: listen的第二个参数并不是用来限制程序的最大连接数的。
而是TCP模块允许的已完成三次握手过程(TCP模块完成)但还没来得及被应用程序accept的最大链接数.
返回值:
成功返回0,错误返回-1