夜间模式暗黑模式
字体
阴影
滤镜
圆角
主题色
socket编程基础知识

创建/删除套接字

socket

#include <sys/socket.h>
int socket(int domain, int type, int protocol);

socket()函数用来创建一个套接字。
返回一个指向该套接字的非负的套接字描述符,若失败则返回-1。
其参数:

  • domain:指定协议族,我们这里只关注两种,即AF_INET(IPV4)和AF_INET6(IPV6),其中AF可替换为PF

  • type:指定套接字类型,我们这里关注两种:

    • SOCK_STREAM:Provides sequenced, reliable, two-way connection-based byte streams. An out-of-band data transmissionmechanism may be supported.

    • SOCK_DGRAM : Supports datagrams (connectionless, unreliable messages of a fixed maximum length).

  • protocol:指定具体的端到端协议,我们关注的有IPPROTO_TCPIPPROTO_UDP ;0为对应type的默认协议。

close

#include <unistd.h>
int close(int fd);

close()函数用来关闭一个文件描述符,这里用来删除一个套接字。
成功则返回0,失败返回-1。

地址信息结构

sockaddr

#include <sys/socket.h>
struct sockaddr {  
     sa_family_t sin_family;//地址族(e.g. AF_INET)
    char sa_data[14]; //与地址族种类相关,包含地址和端口信息              
   }; 

这是一个通用的地址结构。

sockaddr_in

#include<netinet/in.h>

#define sa_family_t unsigned short int
typedef uint32_t in_addr_t;

struct in_addr
  {
    in_addr_t s_addr;//32 bits
  };

/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    sa_family_t sin_family; //AF_INET
    in_port_t sin_port;   /* Port number. 16 bits */
    struct in_addr sin_addr;  /* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[8];
   };   

储存 IPv4 套接字地址,是sockaddr的一个具体实现。在尾部填充字节从而达到与sockaddr大小相同的目的。因此指向sockaddr_in的一个指针可以cast成为指向sockaddr的指针。

sockaddr_in6

储存 IPv6 套接字地址,与sockaddr_in结构相似,这里不做介绍。

补充:sockaddr_in6结构体大小要大于sockaddr的大小,因此后者无法兼容前者。对于这个问题,有新的大小更大的结构体sockaddr_storage

struct sockaddr_storage{
    sa_family_t;
    ...
    Padding and fields to get correct length and alignment.
    ...
};

代替sockaddr作为通用地址结构,这个结构可以兼容IPv6地址。

地址结构转换(Binary/String)

inet_pton

#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);

convert IPv4 and IPv6 addresses from text to binary form.

This function converts the character string src into a network address structure in the af address family, then copies the network address structure to dst. The af argument must be either AF_INET or AF_INET6. dst is written in network byte order.

src points to a character string containing an IPv4 network address in dotted-decimal format, “ddd.ddd.ddd.ddd”, where ddd is a decimal number of up to three digits in the range 0 to 255. The address is converted to a struct in_addr and copied to dst, which must be sizeof(struct in_addr) (4) bytes (32 bits) long.

inet_ntop

#include <arpa/inet.h>
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

convert IPv4 and IPv6 addresses from binary to text form

This function converts the network address structure src in the af address family into a character string. The resulting string is copied to the buffer pointed to by dst, which must be a non-null pointer. The caller specifies the number of bytes available in this buffer in the argument size.

src points to a struct in_addr (in network byte order) which is converted to an IPv4 network address in the dotted-decimal format, “ddd.ddd.ddd.ddd”. The buffer dst must be at least INET_ADDRSTRLEN bytes long.

套接字初始连接–connect

#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *foreignAddress, socklen_t addrlen);

基于连接的协议(如TCP)的套接字使用connect()与和地址绑定的套接字进行连接。

前两个参数在前文中均有介绍(见socket()sockaddr),第三个参数为struct sockaddr的大小。

若成功连接则返回0,否则返回-1。

绑定地址–bind

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *localAddress, socklen_t addrlen);

该函数用来将套接字与特定的地址进行绑定。TCP/IP应用中,sockaddr总是指向sockaddr_in或者sockaddr_in6

若成功连接则返回0,否则返回-1。

bind()通常被server使用,但client也使用bind()指定本地地址/端口(TCP client的地址/端口在connect()时确定)。

注意: 必须使用htonl()localAddress从host byte order转化为network byte order。

处理连接

listen

#include <socket.h>
int listen(int sockfd, int queueLimit);

listen()函数使得套接字成为被动套接字,监听客户端发送的连接请求,并将请求压入请求队列等待接受。listen()并不处理请求

queueLimit指定了请求队列的最大长度,其最大值(128)由宏SOMAXCONN定义。若队列满时监听到请求,则返回error,或者在协议支持重传的情况下忽略该消息。

若成功连接则返回0,否则返回-1。

accept

#include <socket.h>
int accept(int sockfd, struct sockaddr *clientAddress, socklen_t *addressLength);

accept()函数将连接请求出列并进行处理,如果请求队列为空则block直到新的请求到来。

当成功处理请求时,accept()将客户端地址写入clientAddress指向的位置。参数addressLength表明了clientAddress指向的结构体的大小(或者说该处可用的空间)。注意到这个这个参数是指针的形式,它在调用结束后返回写入结构体的实际大小。如果addressLength标明的大小不够大,则clientAddress会被截断,同时addressLength返回一个大于调用时指定的值。因此注意在调用accept()前一定进行addressLength的初始化

当处理成功时,函数返回一个非负的套接字描述符。这个描述符指向的套接字与客户端建立了连接。当失败时返回-1。

交流

send

#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

send()函数用于连接状态的套接字发送数据。

参数flags用于更改一些套接字调用的行为,0为默认行为。此处详见man。

函数返回发送数据的大小(byte),若失败则返回-1。

默认行为状态下,send()block直到所有数据发送完毕。

recv

#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

recv()函数用于接收另一个套接字发送的数据。注意这个套接字对连接性没有要求。

默认行为下,recv()block直到一定量的数据被接收。

其他说明参见sned()

注意:调用一次recv()接收到的数据长度并不取决于send()调用的次数或者是buf的大小

暂无评论

发送评论 编辑评论


				
上一篇
下一篇