16(套接字)

2019-02-21 10:44:06 浏览数 (1)

1 套接字描述符

套接字描述符在Unix系统中是用文件描述符实现的。事实上,许多处理文件描述符函数(read和write)都可以处理文件描述符 要创建一个套接字,可以调用socket函数

代码语言:javascript复制
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
        Returns: file (socket) descriptor if OK, 1 on error

参数domain确定通信的特性,通常以AF_开头

参数type确定参数类型

参数protocol通常为0,表示选择默认协议

套接字通信是双向的。可以采用shutdown来禁止套接字上的输入输出

代码语言:javascript复制
#include <sys/socket.h>
int shutdown (int sockfd, int how);
            Returns: 0 if OK, 1 on error

how=SHUT_RD,那么无法从套接字读取数据; how=SHUT_WR,那么无法使用套接字发送数据; how=SHUT_RDWR,那么无法读取和发送数据。 既然可以close套接字,为什么还要shutdown?首先,close只有在最后一个引用被关闭时才释放网络端点。这意味着如果复制一个套接字(比如dup),套接字直到关闭了最后一个引用时才被释放,而shutdown允许使一个套接字处于不活动状态,无论引用他的文件描述符是多少。其次,有时只关闭套接字双向传输中的一个方向会很方便。比如,如果想让进程确定数据发送何时结束,可以关闭该套接字的写端,而读端仍然可以接收数据。

寻址

大端,是指数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中; 小端,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。 处理器字节序和网络字节序之间的转化

代码语言:javascript复制
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostint32);
        Returns: 32-bit integer in network byte order
uint16_t htons(uint16_t hostint16);
        Returns: 16-bit integer in network byte order
uint32_t ntohl(uint32_t netint32);
        Returns: 32-bit integer in host byte order
uint16_t ntohs(uint16_t netint16);
        Returns: 16-bit integer in host byte order

2 将套接字与地址绑定

代码语言:javascript复制
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
            Returns: 0 if OK, 1 on error

可以使用getsockname 来发现绑定到一个套接字的地址

代码语言:javascript复制
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);
        Returns: 0 if OK, 1 on error

alenp指定缓冲区sockaddr 的大小。返回时会被设置为返回地址的大小。

如果套接字已经和对方连接,调用getpeername来找到对方的地址

代码语言:javascript复制
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);
            Returns: 0 if OK, 1 on error

3 建立连接

代码语言:javascript复制
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
             Returns: 0 if OK, 1 on error

服务端调用listen来宣告可以接受连接请求

代码语言:javascript复制
#include <sys/socket.h>
int listen(int sockfd, int backlog);
        Returns: 0 if OK, 1 on error

使用accept获得连接请求并获得连接

代码语言:javascript复制
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len);
Returns: file (socket) descriptor if OK, 1 on error

4 数据传输

三个函数用来发送数据,三个用于接收数据 三个发送数据send,sendto,sendmsg

代码语言:javascript复制
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);
代码语言:javascript复制
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t nbytes, int flags, const struct sockaddr *destaddr, socklen_t destlen);
        Returns: number of bytes sent if OK, 1 on error

和send的区别在于最后制定了目标地址

可以调用带有msghdr结构的sengmsg来指定多重缓冲区传输数据,这和writev很像

代码语言:javascript复制
#include <sys/socket.h>
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
        Returns: number of bytes sent if OK, 1 on error

Msghdr结构有如下成员:

代码语言:javascript复制
struct msghdr {
     void          *msg_name;         /* optional address */
     socklen_t      msg_namelen;      /* address size in bytes */
     struct iovec  *msg_iov;          /* array of I/O buffers */
     int            msg_iovlen;       /* number of elements in array */
     void          *msg_control;      /* ancillary data */
     socklen_t      msg_controllen;   /* number of ancillary bytes */
     int            msg_flags;        /* flags for received message */
     .
};

接收数据有三个recv,recvfrom,recvmsg

代码语言:javascript复制
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
        Returns: length of message in bytes, 0 if no messages are available and peer has done an orderly shutdown, or 1 on error

如果有兴趣定位发送者,可以使用recvfrom来得到数据发送者的源地址

代码语言:javascript复制
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *restrict buf, size_t len, int flags, struct sockaddr *restrict addr, socklen_t *restrict addrlen);
            Returns: length of message in bytes, 0 if no messages are available and peer has done an orderly shutdown, or 1 on error

如果addr非空,它将包含数据发送者的套接字端点地址。当调用recvfrom时,需要设置addrlen参数指向一个包含addr所指套接字缓冲区字节大小的整数。返回时,该整数设为该地址的实际字节大小

为了将接收到的数据送入多个缓冲区,或者想接收辅助数据,可以使用recvmsg

代码语言:javascript复制
#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
            Returns: length of message in bytes, 0 if no messages are available and peer has done an orderly shutdown, or 1 on error

结构msghdr用于指定接收数据的输入缓冲区。

0 人点赞