SOCKET 学习笔记

前言

面经中提到的epoll,涉及到了socket编程。为了深入了解epoll原理,需要首先了解socket编程。socket是进程间通信IPC,就算在网络中也是如此,所以说网络中通信的主体是进程,而不是计算机。socket学习内容一个是如何建立服务器和客户端,一个是如何使用socket API。

fd=socket(domain, type, protocol);

socket调用可以用来创建一个socket,例如
domain可以用来指定ipv4,type可以用来指定tcp,protocol一般是0。

  • domain
    domain是通信范围与通信地址的类型。有下面几个经典类型:
    UNIX IPV4 IPV6,分别对应的参数是AF_UNIX AF_INET AF_INET6。
    domain 的参数都是以AF开头的代表地址簇。PF开头的代表协议簇。本来设计是地址簇和协议簇是多对多的,但是后来实现过程中,一个协议簇和地址簇是一一对应的。所以基本上domain就是指定了协议簇,地址簇也被指定了。

  • type
    socket表示是流还是数据包,其实就是TCP还是UDP。如果是TCP就是SOCK_STREAM,如果是UDP就是SOCK_DGRAM

bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

该调用用于将socket绑定到一个地址上。之后可以发送TCP报文,在一些场合下也可以通过write发送UDP报文,但是只能在该socket上读取对等socket数据。

  • sockaddr
    该结构体有一个整形表示地址类型,然后后面跟着一个char数组。后面可以看到具体传进来的是根据使用场合的其他数据结构,但是是通用的

listen(int sockfd, int backlog)

将一个socket描述符标记为被动。可以被主动socket连接。backlog是用于限制等待连接的数量。

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

accept调用会阻塞并等待在文件描述符sockfd上的接入请求。一旦请求成功,会创建一个新的socket,这个新的socket与对方进行连接。

  • addr
    返回对方的地址
  • addrlen
    传入addr的长度,用于告知能够写入输入的最大长度。

connect(int sockfd, const struct sockaddr * addr, socklen_t addrlen);

将sockfd连接到addr所述的地址上。

close(int fd)

用于关闭连接

read write

用于对sockfd进行读入或读出

recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

sendto(int sockfd, const void *buffer, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

用于发送和接受udp报文。服务器端不能使用listen函数和accept函数,客户端不能使用connect函数。

unix domain

使用上面的API就可以实现本机上通过文件的通信。
unix domain所使用的sockaddr是sockaddr_run,如下表示:

struct sockaddr_un{
    sa_family_t sun_family;
    char sun_path[108];
}

网络字节序

网络字节顺序是按照大端来的,x86是小端结构。转换使用的是如下的函数进行的

  • htons
  • htonl
  • ntohs
  • ntohl
    h是host,n是net,s是16位,l是32位。s和l是short和long,虽然现在已经不再使用这样的标准了。

Internet socket 地址结构

网络下使用的socket地址是sockaddr_in,定义如下

struct sockaddr_in{
    sa_family_t sin_family;
    in_port_t sin_port;
    struct in_addr sin_addr;
    unsigned char __pad[X];
}

可以看出不一样的地方是后面的char数组变成了一个端口和地址。sin是socket Internet的简写,简写的和sun一样很差。

Internet socket 地址转换

字符串式的地址格式和二进制地址格式转换API:

inet_pton(int domain, const char *src, void *addrptr);

该函数用于将src中包含的字符串转换为网络字节的二进制地址,存入addrptr。p是presentation的意思,就是人类方便的地址。

const char * inet_ntop(int domain, const void *addrptr, char *dst_str, size_t len);

该函数执行网络字节的二进制地址转换为人类可读的地址,写入到dst_str中,缓冲区的大小有len传入。

getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct **result);

该函数给定一个主机名和服务器名,返回socket地址和端口号。
getaddrinfo以host、service、hints参数作为输入,其中host参数包括一个主机名或一个以IPV4字符串。service是服务名或者是端口号。该函数的调用之后需要使用freeaddrinfo来释放空间。

getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *host, size_t hostlen, char *service, size_t servlen, int flags);

给定一个socket地址结构,返回一个主机和服务器名的字符串。

setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

sockfd是代表指向套接字的文件描述符。参数level制定了套接字选项所适用的协议。例如TCP或者是IP,这表示选项作用的套接字API层。一般来说,该选项会设置为SOL_SOCKET,表示作用于套接字API层。参数optname表示了我们期待设置的选项,optvalue是用来设置刚刚的选项的值,可以是整数或者是结构体的指针,指向了一个缓冲区,而参数optlen是刚刚那个指针所指向区域的大小。

例如,要设置sockfd为reuseaddr属性时,可以如下调用:

    int reuse = 1;
    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
    {
        err_exit("setsockopt");
    }

getsockopt(int sockfd, int level, int optname, void *optval, socklen_t optlen);

用法和上面一样,只是获取而已。

你可能感兴趣的:(SOCKET 学习笔记)