Unix Socket - 核心函数

本章描述了编写完整的TCP客户端和服务器所需的核心套接字函数。

下图显示了完整的客户端和服务器交互

The socket Function

要执行网络I/O,进程必须做的第一件事是,调用socket函数,指定所需的通信协议类型和协议族,等等。

#include <sys/types.h>
#include <sys/socket.h>

int socket (int family, int type, int protocol);

这个调用返回一个套接字描述符,您可以在以后的系统调用中使用该描述符,或者在出错时返回-1。

Parameters

family − 它指定协议族,是如下所示的常量之一

AF_INET:IPv4 protocols
AF_INET6: IPv6 protocols
AF_LOCAL: Unix domain protocols
AF_ROUTE: Routing Sockets
AF_KEY: Ket socket

本章不涉及除IPv4以外的其他协议。

type - 它指定您想要的套接字类型。它可以取以下值之一

SOCK_STREAM: Stream socket
SOCK_DGRAM: Datagram socket
SOCK_SEQPACKET: Sequenced packet socket
SOCK_RAW: Raw socket

protocol - 参数应该设置为下面给出的特定协议类型,或者0来为给定的family和type组合选择系统的默认值

IPPROTO_TCP: TCP transport protocol
IPPROTO_UDP: UDP transport protocol
IPPROTO_SCTP: SCTP transport protocol

The connect Function

连接功能用于TCP客户端与TCP服务器建立连接

#include <sys/types.h>
#include <sys/socket.h>

 int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

如果成功连接到服务器,则返回0,否则返回-1。

Parameters

sockfd − 它是套接字函数返回的套接字描述符。

serv_addr − 它是一个指向struct sockaddr的指针,其中包含了目的IP地址和端口。

addrlen − 设置为sizeof(struct sockaddr)。

The bind Function

bind函数为套接字分配一个本地协议地址。在互联网协议中,协议地址是32位IPv4地址或128位IPv6地址,以及16位TCP或UDP端口号的组合。此函数仅由TCP服务器调用。

#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, struct sockaddr *my_addr,int addrlen);

如果成功绑定到地址,则返回0,否则返回-1。

Parameters

    sockfd − 它是套接字函数返回的套接字描述符。

    my_addr − 它是一个指向struct sockaddr的指针,其中包含本地IP地址和端口。

    addrlen − 设置大小为sizeof(struct sockaddr).

您可以自动输入您的IP地址和端口

端口号的值为0表示系统将随机选择一个端口,IP地址的值为INADDR_ANY表示服务器的IP地址将自动分配。

server.sin_port = 0;
server.sin_addr.s_addr = INADDR_ANY;

注意:所有1024以下的端口都保留。您可以将端口设置为1024以上,65535以下,除非它们被其他程序使用。

The listen Function

listen函数只由TCP服务器调用,它执行两个操作 −

    - listen函数将一个未连接的套接字转换为被动套接字,表明内核应该接受指向该套接字的传入连接请求。

    - 这个函数的第二个参数指定内核应该为这个套接字队列的最大连接数。

#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd,int backlog);

如果调用成功,则返回0,否则返回-1。

Parameters

    sockfd − 它是套接字函数返回的套接字描述符。

    backlog − 它是允许的连接数。

The accept Function

TCP服务器调用accept函数,从已完成的连接队列的前端返回下一个已完成的连接。呼叫的签名如下 −

#include <sys/types.h>
#include <sys/socket.h>

int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

如果调用成功,则返回一个非负描述符,否则返回-1。返回的描述符被假定为客户端套接字描述符,所有的读写操作都将在这个描述符上完成,以与客户端通信。

Parameters

    sockfd − 它是套接字函数返回的套接字描述符。

    cliaddr −它是一个指向sockaddr结构体的指针,其中包含客户端IP地址和端口。

    addrlen − 设置大小为sizeof(struct sockaddr)。

The send Function

send函数用于通过流套接字或连接的数据报套接字发送数据。如果要在未连接的数据报套接字上发送数据,必须使用sendto()函数。

您可以使用write()系统调用来发送数据。如下

int send(int sockfd, const void *msg, int len, int flags);

这个调用返回发送的字节数,否则它将在出错时返回-1。

Parameters

    sockfd − 它是套接字函数返回的套接字描述符。

    msg − 它是一个指针,指向您想要发送的数据。

    len − 它是您想要发送的数据长度(以字节为单位)。

    flags −它被设置为0。

The recv Function

recv函数用于通过流套接字或连接的数据报套接字接收数据。如果想通过未连接的数据报套接字接收数据,必须使用recvfrom()。

可以使用read()系统调用读取数据。这个调用在帮助函数一章中有解释。

int recv(int sockfd, void *buf, int len, unsigned int flags);

这个调用返回读入缓冲区的字节数,否则它将在出错时返回-1。

Parameters

    sockfd −它是套接字函数返回的套接字描述符。

    buf − 它是读取信息的缓冲区。

    len − 它是缓冲区的最大长度。

    flags − 它被设置为0。

The sendto Function

sendto函数用于在未连接的数据报套接字上发送数据。签名如下

int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);

这个调用返回发送的字节数,否则它返回-1错误。

Parameters

    sockfd − 它是套接字函数返回的套接字描述符。

    msg − 它是一个指针,指向您想要发送的数据。

    len − 它是您想要发送的数据长度(以字节为单位)。

    flags − 它被设置为0。

    to − 它是一个指向struct sockaddr的指针,用于发送数据的主机。

    tolen − 它设置为sizeof(struct sockaddr)。

The recvfrom Function

recvfrom函数用于从未连接的数据报套接字接收数据。

int recvfrom(int sockfd, void *buf, int len, unsigned int flags struct sockaddr *from, int *fromlen);

这个调用返回读入缓冲区的字节数,否则返回-1。

Parameters

    sockfd − 它是套接字函数返回的套接字描述符。

    buf − 它是读取信息的缓冲区。

    len − 它是缓冲区的最大长度。

    flags − 它被设置为0。

    from − 它是一个指向struct sockaddr的指针,用于读取数据的主机。

    fromlen − 它设置为sizeof(struct sockaddr)。

The close Function

关闭功能用于关闭客户端和服务器之间的通信。其语法为

int close( int sockfd );

如果调用成功,则返回0,否则返回-1。

Parameters

    sockfd − 它是套接字函数返回的套接字描述符。

The shutdown Function

shutdown功能用于优雅地关闭客户端和服务器之间的通信。与close函数相比,这个函数提供了更多的控制。下面给出了shutdown的语法

int shutdown(int sockfd, int how);

如果调用成功,则返回0,否则返回-1。

Parameters

    sockfd − 它是套接字函数返回的套接字描述符。

    how − 下面其中一个

        0 − 表示不允许接收

        1 − 表示不允许发送

        2 − 表示发送和接收都不允许。当how设置为2时,它和close()是一样的。

The select Function

select函数指示指定的文件描述符中哪些可以读,哪些可以写,或者有一个等待的错误条件。

当应用程序调用recv或recvfrom时,它将被阻塞,直到该套接字的数据到达。当传入的数据流为空时,应用程序可以进行其他有用的处理。另一种情况是应用程序从多个套接字接收数据。

在输入队列中没有数据的套接字上调用recv或recvfrom会阻止从其他套接字上立即接收数据。select函数调用通过允许程序轮询所有套接字句柄来解决这个问题,以查看它们是否可用于非阻塞的读写操作。

下面给出select的语法 

int select(int  nfds, fd_set  *readfds, fd_set  *writefds, fd_set *errorfds, struct timeval *timeout);

如果调用成功,则返回0,否则返回-1。

Parameters

    nfds −它指定要测试的文件描述符的范围。select()函数测试范围为0到nfds-1的文件描述符

    readfds − 它指向一个fd_set类型的对象,该对象在输入时指定要检查的文件描述符是否准备读取,在输出时指定哪些文件描述符准备读取。它可以为NULL,表示为空集。

    writefds − 它指向一个fd_set类型的对象,该对象在输入时指定要检查的文件描述符是否准备写入,在输出时指定哪些文件描述符准备写入。它可以为NULL,表示为空集。

    exceptfds − 它指向一个fd_set类型的对象,该对象在输入时指定要检查的文件描述符是否有错误条件等待处理,在输出时指定哪些文件描述符有错误条件等待处理。它可以为NULL,表示为空集。

    timeout − 它指向一个timeval结构体,该结构体指定select调用应该为一个可用的I/O操作轮询描述符多长时间。如果超时值为0,则select将立即返回。如果timeout参数为NULL,则select将阻塞,直到至少有一个文件/套接字句柄为可用的I/O操作准备好为止。否则,select将在超时时间已经过去或至少有一个文件/套接字描述符准备好进行I/O操作之后返回。

select的返回值是文件描述符集中指定的准备好进行I/O的句柄数。如果达到timeout字段指定的时间限制,则选择返回0。以下宏用于操作文件描述符集 

    FD_CLR(fd, &fdset) − 清除文件描述符集fdset中文件描述符fd的位。

    FD_ISSET(fd, &fdset) − 如果文件描述符fd的位设置在fdset所指向的文件描述符集合中,则返回一个非零值,否则返回0。

    FD_SET(fd, &fdset) − 在文件描述符集合fdset中设置文件描述符fd的位。

    FD_ZERO(&fdset) − 初始化文件描述符集fdset,使所有文件描述符的位都为零。

如果fd参数小于0或大于等于FD_SETSIZE,这些宏的行为是未定义的。

Example

fd_set fds;

struct timeval tv;

/* do socket initialization etc.
tv.tv_sec = 1;
tv.tv_usec = 500000;

/* tv now represents 1.5 seconds */
FD_ZERO(&fds);

/* adds sock to the file descriptor set */
FD_SET(sock, &fds);

/* wait 1.5 seconds for any data to be read from any single socket */
select(sock+1, &fds, NULL, NULL, &tv);

if (FD_ISSET(sock, &fds)) { 
     recvfrom(s, buffer, buffer_len, 0, &sa, &sa_len); 
     /* do something */
}else { 
     /* do something else *0/
}

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容