1.socket函数
(1)定义
作用:创建socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
(2)参数
- domain
设置网络通信域,即通信的协议设置:
名称 | 含义 |
AF_UNIX, AF_LOCAL | 本地通信 |
AF_INET | IPv4 Internet协议 |
AF_INET6 | IPv6 Internet协议 |
AF_IPX | IPX-Novell协议 |
AF_NETLINK | 内核用户界面设备 |
AF_X25 | ITU-T X25 / ISO-8208协议 |
AF_AX25 | Amateur radio AX.25 |
AF_ATMPVC | 原始ATM PVC访问 |
AF_APPLETALK | Appletalk |
AF_PACKET | 底层包访问 |
AF_ALG | 内核加密API |
- type
参数type用于设置套接字通信的类型:
名称 | 含义 |
SOCK_STREAM | TCP连接(提供序列化的、可靠的、双向连接的字节流,支持带外数据传输) |
SOCK_DGRAM | UDP连接(无连接状态、不可靠的报文) |
SOCK_SEQPACKET | 序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统调用时数据需要将全部数据读出 |
SOCK_RAW | RAW类型,提供原始网络协议访问 |
SOCK_RDM | 提供可靠的数据报文,不过可能数据会有乱序 |
- protocol
用于制定某个协议的特定类型.
例如创建一个流式的socket:
int fd = socket(AF_INET, SOCK_STREAM, 0);
(3)返回值
返回值中fd>0代表创建成功,此时fd的值就是创建文件描述符的值;fd = -1表示创建失败,可以通过errno来查看具体失败原因。
errno值 | 含义 |
EACCES | 没有权限建立制定的domain的type的socket |
EAFNOSUPPORT | 不支持所给的地址类型 |
EINVAL | 不支持此协议或者协议不可用 |
EMFILE | 进程文件表溢出 |
ENOBUFS or ENOMEM | 内存不足,socket只有到资源足够或者有进程释放内存 |
EPROTONOSUPPORT | 制定的协议type在domain中不存在 |
2.bind函数
(1)定义
作用:套接字与一个地址相关联,即地址绑定。
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
(2)参数
- sockfd
上一步socket创建的返回值fd(前提创建成功了)
- sockaddr
sockaddr结构体定义如下:
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
这个数据结构逐渐被舍弃(参考:https://blog.csdn.net/ZWE7616175/article/details/80252048)
代替的是:struct sockaddr_in,在使用的时候需要把第二个结构强转成sockaddr
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
上面的不太直观,翻译一下:
struct sockaddr_in {
uint8_t sa_len; /* 结构体长度*/
short int sin_family; /* 通信类型 */
unsigned short int sin_port; /* 端口 */
struct in_addr sin_addr; /* Internet 地址 */
unsigned char sin_zero[8]; /* 未使用的*/
};
struct in_addr { //sin_addr的结构体类型in_addr 原型
unsigned long s_addr; /*存4字节的 IP 地址(使用网络字节顺序)。*/
};
- sddrlen
addr结构的长度。
(3)返回值
返回值为0时表示绑定成功,-1表示绑定失败,errno的错误值:
errno值 | 含义 |
EACCES | 地址被保护,用户的权限不足 |
EADDRINUSE | 给定地址已经使用 |
EBADF | sockfd不合法 |
EINVAL | sockfd已经绑定到其他地址 |
ENOTSOCK | 描述符不是socket描述符 |
EADDRNOTAVAIL | 接口不存在或者绑定地址不是本地 |
EFAULT | addr指针超出用户空间 |
ELOOP | 解析addr时符号链接过多 |
ENAMETOOLONG | addr过长 |
ENOENT | 文件不存在 |
ENOMEM | 内核内存不够 |
ENOTDIR | 不是目录 |
EROFS | 只读 |
例如:
struct sockaddr_in bindaddr;
bindaddr.sin_family = AF_INET;
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bindaddr.sin_port = htons(8080);
if (bind(fd, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) == -1)
{
pinttf("bind failed!\n");
return -1;
}
3.listen
(1)定义:listen()函数将sockfd标记为被动打开的套接字(即变为监听状态),并作为accept的参数用来接收到达的连接请求。
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
(2)参数:
- sockfd
socket类型的文件描述符。
- backlog
用来描述sockfd的等待连接队列能够达到的最大值。
(3)返回值
返回值为0时表示成功,-1表示失败,errno的错误值:
errno值 | 含义 |
EADDRINUSE | 另一个套接字已经绑定在相同的端口上 |
EBADF | sockfd不是有效的文件描述符 |
ENOTSOCK | sockfd不是套接字 |
EOPNOTSUPP | sockfd不是支持listen操作的套接字类型 |
4.connect
(1)定义
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
(2)参数
- sockfd
套接字文件描述符
- sockaddr
参照struct sockaddr_in(目的地址的IP和端口信息)
- addrlen
填sizeof(struct sockaddr_in)
(3)返回值
返回值为0时表示成功,-1表示失败,errno的错误值:
errno值 | 含义 |
EACCES | 没有权限建立制定的domain的type的socket |
EBADF | 无效的socket文件描述符 |
EISCONN | 已经连接过了 |
ETIMEDOUT | 超时 |
5.accept
(1)定义:
尝试接收一个连接
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/socket.h>
int accept4(int sockfd, struct sockaddr *addr,
socklen_t *addrlen, int flags);
(2)参数
- sockfd
socket类型的文件描述符
- sockaddr
参照struct sockaddr_in
(3)返回值
成功时,返回非负整数,该整数是接收到套接字的描述符;出错时,返回-1,相应地设定全局变量errno:
errno值 | 含义 |
EFAULT | |
ENOTSOCK | |
EOPNOTSUPP | |
EPERM | 防火墙拒绝此连线 |
ENOBUFS | 系统的缓冲内存不足 |
6.send
(1)定义
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
(2)参数
- sockfd
如果是服务端这个sockfd是accept函数返回的fd
- buf
待发送的缓存
- len
send指要发送的长度
- flags
(3)返回值
返回值>0表示发送的字节数,=0表示对端断开连接,返回-1时:在阻塞模式下为错误,而在非阻塞模式下不一定是错误的,所以要结合errno值来判断。
errno值 | 含义 |
EAGAIN or EWOULDBLOCK | 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时 |
EINTR | 操作被信号中断 |
7.recv
(1)定义
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
(2)参数
- sockfd
如果是服务端这个sockfd是accept函数返回的fd
- buf
待接收的缓存
- len
recv指期望接收的长度
- flags
flags值 | 含义 |
MSG_DONTWAIT | 仅本操作非阻塞 |
MSG_OOB | 发送或接收带外数据 |
MSG_PEEK | 窥看外来消息 |
MSG_WAITALL | 等待所有数据 |
(3)返回值
返回值>0表示发送的字节数,=0表示对端断开连接,返回-1时:在阻塞模式下为错误,而在非阻塞模式下不一定是错误的,所以要结合errno值来判断。
errno值 | 含义 |
EAGAIN or EWOULDBLOCK | 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时 |
EINTR | 操作被信号中断 |