套接字描述符
#include
int socket(int domain, int type, int protocol);
domain
协议族:
AF_INETipv4
AF_INET6ipv6
AF_UNIX unix域
type
套接字类型
SOCKET_STREAM 流式字节流,tcp时使用这个
SOCKET_DGRAM 固定长度,无连接,不可靠协议 UDP使用这个
SOCKET_SEQPACKET 长度固定,有序可靠,面向连接的报文 ,读发的字节数是相等的
SOCKET_RAW 允许直接操作IP,需要root权限
type == 0 时使用默认协议 tcp udp,,,
#include
int shutdouwn(int fd, int how);
SHUTDOWN_RD 关闭读
SHUTDOWN_WR 关闭写
SHUTDOWN_RDWR 关闭读写
相对于close 只有所有引用socket描述符(dup dup2)的都关闭才能关闭文件
shutdown 可以控制socket与 描述符引用无关!
方便控制写,读
字节序
由于历史原因,tcp/ip的字节序是打算字节序
现在很多服务器,pc都是小端序,so为支持tcp/ip,地址端口必须转换为网络地址序(大端序)
对于数据,只要发送端和接收端都是小端序就没问题!
#include
uint32_t htonl(uni32_t hostint32);//ip用这个
uint16_t htons(uni16_t hostint16);//端口用这个
uint32_t ntohl(uni32_t net32);//网络序转换成小端序 ip
uint16_t ntohl(uni32_t net16);//网络序转换成小端序 端口用
地址格式
struct sockaddr
{
sa_family_t sa_family;
char sa_data[];
...
};
struct in_addr
{
in_addr s_addr;//ipv4的地址
};
struct sockaddr_in
{
sa_family_t sin_family;//地址族
in_port_t sin_port;
struct in_addr sin_addr;//ip地址
};
family ipv4 AF_INET
ipv6 AF_INET6
由于历史原因,在bind和connect中地址都强制转换成sockaddr
#include
const char* inet_ntop(int domain, const void*restrict addr, const char *restrict str, socklen_t bufsize);
socksize str缓冲区大小,防止越界
成功返回转换后的字符串,失败返回NULL
int inet_pton(int domain, const char* restrict str, void *restrict addr);
成功返回0,失败返回-1
转换后的结果存放在add指向的地址r中
套接字绑定地址
O_NOBLOCK#include
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
len 表示addr的字节长度
地址端口号必须>=1024,在root权限下可以 < 1024
必须绑定本机的地址
INADDR_ANY可以绑定到本机安装的所有网卡
可以通过getsockname 获取fd上绑定的地址,若fd未绑定地址则结果未定义
#include
int getsocketname(int fd, struct sockaddr *restrict addr, socklen_t *alenp);
alenp填充返回的addr的字节数
地址通过addr返回
如果addr缓冲区大小不匹配,自动截断,不报错
int getpeername(int fd, struct sockaddr *restrict addr, socklen_t *alenp);
返回链接另一端的地址信息
int connect(int sockfd, struct sockaddr *addr, socklen_t len);
客户端可以向指定的服务器地址尝试建立连接
若服务器端,未运行可接受连接,则返回-1
对udp也可以用此函数,则此函数会将fd与目的端地址绑定
在linux下如果连接失败,还可以继续使用fd再次连接,但在有些系统中,不能再用需要用socket函数产生一个新的fd
若果是为了可移植性,需要在失败后在socket()
int listen(int fd, int backlog);
在服务器端用此函数
此函数backlog设置fd,在三次握手未成功,和刚建立连接的队列的最大排队值 tcp默认128
int accept(int fd, struct socketaddr *restrict addr, socklen_t len);
用于TCP
监听连接connect请求,客户端的地址填充到addr中,len表示addr的字节数
在fd未设置O_NOBLOCK时,阻塞直到连接请求到来
若fd设置了O_NOBLOCK,则返回-1,errno EWOULDBLOCK
成功返回一个新的 socket fd连接到客户端
tcp中有 用于accept的fd 绑定到本机的ip,用于接受连接请求
还有直接连接客户端的fd,读写的数据都是发送到客户端,读客户端的数据
accept的fd accept成功 返回连接到客户端的fd
TCP socket的服务器端& 客户端代码顺序
服务端
int fd = socket()产生一个socketfd
设置地址信息sockaddr_in ip 端口
bind(fd, &addr, len)绑定fd与本地地址
listen 设置可正在握手,和刚握手成功的等待队列大小
rwfd = accept
读写 fd
客户端
int fd = socket()产生一个socketfd
设置地址信息sockaddr_in ip 端口
connect
用fd读写
套接字选项
套接字机制使用了set 和get函数,来获取和设置socket的
通用套接字选项
套接字层次管理的选项
特定协议选项
int setsockopt(int fd, int level, int op, const void *val, sock_len len);
int getsockopt(int fd, int level, int op, void * val, socklen_t lenp);