socket()
int socket(int domain, int type, int protocol);
返回值应大于等于0,小于零则创建失败
socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而**socket()**用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。
domain
? 即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
可以选择的协议族:
- AF_UNIX, AF_LOCAL:本地通信
- AF_INET :IPv4
- AF_INET6 :IPv6要自己的ip协议的版本支持IPV6
- AF_IPX :IPX - Novell 协议
- AF_NETLINK :内核用户界面设备
- AF_X25 :ITU-T X.25 / ISO-8208 协议
- AF_AX25 :业余无线电 AX.25 协议
- AF_ATMPVC :访问原始 ATM PVC
- AF_APPLETALK :AppleTalk
- AF_PACKET :底层数据包接口
- AF_ALG :内核加密 API 的 AF_ALG 接口
type
? socket的类型:
SOCK_STREAM:提供可靠的(即能保证数据正确传送到对方)面向连接的 Socket 服务,多
用于资料(如文件)传输,如 TCP 协议;(只有TCP提供这种可靠服务)
SOCK_DGRAM:是提供无保障的面向消息的 Socket 服务,主要用于在网络上发广播信息,
如 UDP 协议,提供无连接不可靠的数据报交付服务。
SOCK_RAW:表示原始套接字,它允许应用程序访问网络层的原始数据包;
SOCK_RDM:提供不保证排序的可靠数据报层。
protocol
? 故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议(这个协议我将会单独开篇讨论!)。protocal的值一般均为0。
bind()
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
? bind()函数用于将一个IP地址或端口号与一个套接字进行绑定,许多时候内核会帮我们自动绑定一个 IP 地址与端口号;只有用户进程想与一个具体的地址或端口相关联的时候才需要调用这个函数,一般程序依赖内核的自动选址的方式来自动完成地址选择。
参数:
? ? sockfd:sockfd 是由 socket() 函数返回的套接字描述符。
? ? my_addr:my_addr 是一个指向套接字地址结构的指针。
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
? ? addrlen:addrlen 指定了以 addr 所指向的地址结构体的字节长度。
struct sockaddr_in {
short int sin_family; /* 协议族 */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* IP 地址 */
unsigned char sin_zero[8]; /* sin_zero 是为了让 sockaddr 与sockaddr_in 两个数据结构保持大小相同而保留的空字节 */
};
connect()
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
connect()函数运用于客户端,将sockfd与远程ip地址、端口号进行绑定;参数和bind()一样。connect()是套接字连接操作,对TCP协议来说,connect函数操作成功之后代表对应的套接字已经和远程主机进行了连接,可以发送和接受数据。在UDP()协议中,没有连接的概念。
listen()
int listen(int s, int backlog);
listen()只能用于TCP服务器进程中使用,让服务器进入监听状态,等待客户端的连接请求,listen()一般在bind()之后,accept()之前进行调用;
参数:
? ? sockfd:sockfd 是由 socket() 函数返回的套接字描述符。
? ? backlog 参数用来描述 sockfd 的等待连接队列能够达到的最大值。
accept()
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
? 为了能够正常让 TCP 客户端能正常连接到服务器,服务器必须遵循以下流程处理:
-
调用 socket() 函数创建对应的套接字类型。 -
调用 bind() 函数将套接字绑定到本地的一个端口地址。 -
调用 listen() 函数让服务器进程进入监听状态,等待客户端的连接请求。 -
调用 accept() 函数处理到来的连接请求。
accept() 函数用于 TCP 服务器中,等待着远端主机的连接请求,并且建立一个新的 TCP 连接,在调用这个函数之前需要通过调用 listen() 函数让服务器进入监听状态,如果队列中没有未完成连接套接字,并且套接字没有标记为非阻塞模式,accept() 函数的调用会阻塞应用程序直至与远程主机建立 TCP 连接;如果一个套接字被标记为非阻塞式而队列中没有未完成连接套接字, 调用accept() 函数将立即返回 EAGAIN。
? accept() 函数就是用于处理连接请求的,它会从未完成连接队列中取出第一个连接请求,建一个和参数 s 属性相同的连接套接字,并为这个套接字分配一个文件描述符, 然后以这个描述符返回。
read()
? 接收网络中的数据函数可以是 read()、recv()、recvfrom() 等。
ssize_t read(int fd, void *buf, size_t count);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
write()
? 向套接字中写入count字节的数据
ssize_t write(int fd, const void *buf, size_t count);
返回值大于0,小于0出错
send()
? 用于发送数据,客户端和服务器都可以用。
int send(int s, const void *msg, size_t len, int flags);
参数:
? ? s:指定发送端套接字描述符。
? ? msg:指定要发送数据的缓冲区。
? ? len:指明实际要发送的数据的字节数。
? ? flflags:一般设置为 0 即可
sendto()
int sendto(int s, const void *msg, size_t len, int flags, const struct , sockaddr *to, socklen_t tolen);
sendto() 函数与 send 函数非常像,但是它会通过 struct sockaddr 指向的 to 结构体指定要发送给哪个远端主机,在 to 参数中需要指定远端主机的 IP 地址、端口号等,而 tolen 参数则是指定 to 结构体的字节长度。
|