牛客项目第四章-网络编程—学习记录

CS架构:客户端服务器

image.png

BS架构:浏览器服务器

image.png

网卡(网络适配器):拥有MAC地址

功能 :
:::info
1)数据的封装与解封装
2)链路管理
3)数据编码与译码
:::
IP地址编码方式
image.png
子网掩码:将某个 IP 地址划分成网络地址和主机地址两部分。

端口:就是给缓冲区起个名
应用程序可以有多个端口号
端口号:标识应用程序的进程,不能用PID,因为PID是动态变化的

7层OSI模型
image.png
**TCP/IP四层模型:**上层协议使用下层协议提供的服务
image.png
TTL(生存时间):防止无用消息一直存在使网络拥堵,经过一个路由就-1,为0就没了

网络通信的过程
image.png
DNS:通过域名解析目标IP地址:192.168.1.2
ARP:通过IP地址查找MAC地址,通过192.168.1.2找到0a:0b:0c:0d:0e:0f
RARP:通过MAC地址查找IP地址

ARP:在局域网发送的广播信息,192.168.1.2问:谁的IP地址是192.168.1.3?告诉我你的MAC地址
image.png
image.png
ff.ff.ff.ff.ff.ff:就是广播
image.png

socket:是一套通信的接口

1)不同主机之间进程通信的方式
2)是由IP地址和端口结合的
3)上联应用进程,下联网络协议栈

:::info
在 Linux 环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。可以使用文件描述符引用套接字。与管道类似的,Linux 系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。
image.png
:::

**字节序,**内存地址增长方向是高地址

image.png
当格式化的数据在两台使用不同字节序的主机之间直接传递时,接收端必然错误的解释之。
解决方法是:发送端总是把要发送的数据转换成大端字节序数据后再发送,而接收端知道对方传送过来的数据总是采用大端字节序,所以接收端可以根据自身采用的字节序决定是否对接收到的数据进行转换(小端机转换,大端机不转换)。
image.png

#include <arpa/inet.h>
    // 转换端口
    uint16_t htons(uint16_t hostshort);     // 主机字节序 - 网络字节序
    uint16_t ntohs(uint16_t netshort);      // 网络字节序 - 主机字节序 


    // 转IP
    uint32_t htonl(uint32_t hostlong);      // 主机字节序 - 网络字节序
    uint32_t ntohl(uint32_t netlong);       // 网络字节序 - 主机字节序
**socket 地址 **

:::info
1)socket地址其实是一个结构体,封装端口号和IP等信息。后面的socket相关的api中需要使用到这个
socket地址。
2)客户端 -> 服务器(IP, Port)
:::
IP地址转换(字符串ip-整数 ,主机、网络字节序的转换 )

#include <arpa/inet.h>
// p:点分十进制的IP字符串,n:表示network,网络字节序的整数
int inet_pton(int af, const char *src, void *dst);
af:地址族: AF_INET AF_INET6
src:需要转换的点分十进制的IP字符串
dst:转换后的结果保存在这个里面
// 将网络字节序的整数,转换成点分十进制的IP地址字符串
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
af:地址族: AF_INET AF_INET6
src: 要转换的ip的整数的地址
dst: 转换成IP地址字符串保存的地方
size:第三个参数的大小(数组的大小)
返回值:返回转换后的数据的地址(字符串),和 dst 是一样的 
 
TCP和UDP的区别

image.png

**TCP通信流程 **

image.png
image.png
image.png

套接字函数

:::info
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h> // 包含了这个头文件,上面两个就可以省略
int socket(int domain, int type, int protocol);

  • 功能:创建一个套接字
  • 参数:
    1. domain: 协议族
      AF_INET : ipv4
      AF_INET6 : ipv6
      AF_UNIX, AF_LOCAL : 本地套接字通信(进程间通信)
    2. type: 通信过程中使用的协议类型
      SOCK_STREAM : 流式协议
      SOCK_DGRAM : 报式协议
    3. protocol : 具体的一个协议。一般写0
      1. SOCK_STREAM : 流式协议默认使用 TCP
      2. SOCK_DGRAM : 报式协议默认使用 UDP
    4. 返回值:
      1. 成功:返回文件描述符,操作的就是内核缓冲区。
      2. 失败:-1

*int bind(int sockfd, const struct sockaddr addr, socklen_t addrlen); // socket命名

  • 功能:绑定,将fd 和本地的IP + 端口进行绑定
  • 参数:
    1. sockfd : 通过socket函数得到的文件描述符
    2. addr : 需要绑定的socket地址,这个地址封装了ip和端口号的信息
    3. addrlen : 第二个参数结构体占的内存大小

int listen(int sockfd, int backlog); // /proc/sys/net/core/somaxconn

  • 功能:监听这个socket上的连接
  • 参数:
    1. sockfd : 通过socket()函数得到的文件描述符
    2. backlog : 未连接的和已经连接的和的最大值, 5

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

  • 功能:接收客户端连接,默认是一个阻塞的函数,阻塞等待客户端连接
  • 参数:
    1. sockfd : 用于监听的文件描述符
    2. addr : 传出参数,记录了连接成功后客户端的地址信息(ip,port)
    3. addrlen : 指定第二个参数的对应的内存大小
  • 返回值:
    • 成功 :用于通信的文件描述符
    • -1 : 失败

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

  • 功能: 客户端连接服务器
  • 参数:
    1. sockfd : 用于通信的文件描述符
    2. addr : 客户端要连接的服务器的地址信息
    3. addrlen : 第二个参数的内存大小
  • 返回值:成功 0, 失败 -1

ssize_t write(int fd, const void buf, size_t count); // 写数据
ssize_t read(int fd, void buf, size_t count); // 读数据

:::
TCP三次握手
第一个ACK代表客户端的发与服务端的收没问题,第二个ACK代表客户端的收与服务端的发没问题
第一次握手客户端不可以携带通信的数据,可以携带报文的数据,第二次握手之后客户端可以携带通信的数据
image.png
image.png
image.png
image.png
TCP滑动窗口
:::info
1)滑动窗口(Sliding window)是一种流量控制技术。
2)早期的网络通信中,通信双方不会考虑网络的拥挤情况
直接发送数据**。由于大家不知道网络拥塞状况,同时发送数据,导致中间节点阻塞掉包,谁也发不了数据,所以就有了滑动窗口机制来解决此问题。
3)滑动窗口协议是用来改善吞吐量的一种技术,即容许发送方在接收任何应答之前传送附加的包。接收方告诉发送方在某一时刻能送多少包(称窗口尺寸)。
4)TCP 中采用滑动窗口来进行传输控制,滑动窗口的大小意味着接收方还有多大的缓冲区可以用于接收数据。发送方可以通过滑动窗口的大小来确定应该发送多少字节的数据。当滑动窗口为 0时,发送方一般不能再发送数报。
5)滑动窗口是 TCP 中实现诸如 ACK 确认、流量控制、拥塞控制的承载结构。
:::

  • 窗口理解为缓冲区的大小
  • 滑动窗口的大小会随着发送数据和接收数据而变化。
  • 通信的双方都有发送缓冲区和接收数据的缓冲区
    服务器:
    发送缓冲区(发送缓冲区的窗口)
    接收缓冲区(接收缓冲区的窗口)
    客户端:
    发送缓冲区(发送缓冲区的窗口)
    接收缓冲区(接收缓冲区的窗口)
    image.png
    :::info
    发送方的缓冲区:
    白色格子:空闲的空间
    灰色格子:数据已经被发送出去了,但是还没有被接收
    紫色格子:还没有发送出去的数据
    接收方的缓冲区:
    白色格子:空闲的空间
    紫色格子:已经接收到的数据
    :::
    image.png
# mss: Maximum Segment Size(一条数据的最大的数据量)
# win: 滑动窗口
1. 客户端向服务器发起连接,客户端的滑动窗口是4096,一次发送的最大数据量是1460
2. 服务器接收连接情况,告诉客户端服务器的窗口大小是6144,一次发送的最大数据量是1024
3. 第三次握手
4. 4-9 客户端连续给服务器发送了6k的数据,每次发送1k
5.10次,服务器告诉客户端:发送的6k数据已经接收到,存储在缓冲区中,缓冲区数据已经处理了2k,窗口大小是2k
6.11次,服务器告诉客户端:发送的6k数据已经接收到,存储在缓冲区中,缓冲区数据已经处理了4k,窗口大小是4k
7.12次,客户端给服务器发送了1k的数据
8.13次,客户端主动请求和服务器断开连接,并且给服务器发送了1k的数据
9.14次,服务器回复ACK 8194, a:同意断开连接的请求 b:告诉客户端已经接受到方才发的2k的数据c:滑动口2k
10.1516次,通知客户端滑动窗口的大小
11.17次,第三次挥手,服务器端给客户端发送FIN,请求断开连接
12.18次,第四次挥手,客户端同意了服务器端的断开请求 
TCP四次挥手

image.png
:::info
四次挥手发生在断开连接的时候,在程序中当调用了close()会使用TCP协议进行四次挥手。
客户端和服务器端都可以主动发起断开连接,谁先调用close()谁就是发起。
因为在TCP连接的时候,采用三次握手建立的的连接是双向的,在断开的时候需要双向断开。
:::
image.png

TCP通信并发

并发:一台咖啡机,2个人轮流接咖啡
并行:两台咖啡机,2个人同时接咖啡
:::info
要实现TCP通信服务器处理并发的任务,使用多线程或者多进程来解决。
思路:

  1. 一个父进程,多个子进程
    2.父进程负责等待并接受客户端的连接(accept)
    3.子进程:完成通信,接受一个客户端连接,就创建一个子进程用于通信。
    :::
    TCP状态转换
    image.png
    Linux下观察状态变化
    1)启动服务器
    image.png
    2)启动客户端,4125服务器是监听用的,4132是服务器通信用的
    image.png
    3)主动关闭服务器,服务器进入FIN_WAIT2状态,客户端进入CLOSE_WAIT状态
    image.png
    4)过了2MSL后,服务器才断开连接。
    image.png
    image.png
#include <sys/socket.h>
int shutdown(int sockfd, int how);
sockfd: 需要关闭的socket的描述符
how: 允许为shutdown操作选择以下几种方式:
SHUT_RD(0): 关闭sockfd上的读功能,此选项将不允许sockfd进行读操作。
该套接字不再接收数据,任何当前在套接字接受缓冲区的数据将被无声的丢弃掉。
SHUT_WR(1): 关闭sockfd的写功能,此选项将不允许sockfd进行写操作。进程不能在对此套接字发
出写操作。
SHUT_RDWR(2):关闭sockfd的读写功能。相当于调用shutdown两次:首先是以SHUT_RD,然后以
SHUT_WR。 

使用 close 中止一个连接,但它只是减少描述符的引用计数,并不直接关闭连接,只有当描述符的引用
计数为 0 时才关闭连接。shutdown 不考虑描述符的引用计数,直接关闭描述符。也可选择中止一个方向的连接,只中止读或只中止写。
注意:

  1. 如果有多个进程共享一个套接字,close 每被调用一次,计数减 1 ,直到计数为 0 时,也就是所用进程都调用了 close,套接字将被释放。
  2. 在多进程中如果一个进程调用了 shutdown(sfd, SHUT_RDWR) 后,其它的进程将无法进行通信。
    但如果一个进程 close(sfd) 将不会影响到其它进程。
端口复用

:::info

  1. 防止服务器重启时之前绑定的端口还未释放
  2. 程序突然退出而系统没有释放端口
    :::
#include <sys/types.h>
#include <sys/socket.h>
// 设置套接字的属性(不仅仅能设置端口复用)
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t
optlen);
参数:   ● sockfd : 要操作的文件描述符
        ● level : 级别 - SOL_SOCKET (端口复用的级别)
        ● optname : 选项的名称
        ● SO_REUSEADDR
        ● SO_REUSEPORT
        ● optval : 端口复用的值(整形)
        ● 1 : 可以复用
        ● 0 : 不可以复用
        ● optlen : optval参数的大小
端口复用,设置的时机是在服务器绑定端口之前。
        setsockopt();
        bind();
常看网络相关信息的命令
netstat 
参数:
    -a 所有的socket
    -p 显示正在使用socket的程序的名称
    -n 直接使用IP地址,而不通过域名服务器  
查看指定的端口的网络信息:netstat -anp |grep 9999
I/O多路复用(I/O多路转接)

:::info
I/O 多路复用使得程序能同时监听多个文件描述符,能够提高程序的性能,Linux 下实现 I/O 多路复用的系统调用主要有 select、poll 和 epoll。
:::

阻塞等待(BIO模型):一直阻塞等着快递员送达快递,期间啥也不干。
优化:多进程开分身取快递
image.png
image.png
非阻塞(NIO模型),轮询,隔时间轮流询问快递员快递到没到,到了处理。
image.png
image.png
IO多路复用select/poll:找一个菜鸟驿站代收,告诉你有几个快递到了
image.png
IO多路复用epoll:找一个菜鸟驿站代收,告诉你有几个快递到了,分别是什么什么。
image.png

select

主旨思想:
:::info

  1. 首先要构造一个关于文件描述符的列表,将要监听的文件描述符添加到该列表中。
  2. 调用一个系统函数,监听该列表中的文件描述符,直到这些描述符中的一个或者多个进行I/O
    操作时,该函数才返回。
    a.这个函数是阻塞
    b.函数对文件描述符的检测的操作是由内核完成的
  3. 在返回时,它会告诉进程有多少(哪些)描述符要进行I/O操作。
    :::
// sizeof(fd_set) = 128 1024
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
int select(int nfds, fd_set readfds, fd_set writefds,fd_set exceptfds, struct timeval timeout);
● 参数:
    ● nfds : 委托内核检测的最大文件描述符的值 + 1
    ● readfds : 要检测的文件描述符的读的集合,委托内核检测哪些文件描述符的读的属性
        ● 一般检测读操作
        ● 对应的是对方发送过来的数据,因为读是被动的接收数据,检测的就是读缓冲区
        ● 是一个传入传出参数
    ● writefds : 要检测的文件描述符的写的集合,委托内核检测哪些文件描述符的写的属性
    		 ● 委托内核检测写缓冲区是不是还可以写数据(不满的就可以写)
    ● exceptfds : 检测发生异常的文件描述符的集合
    ● timeout : 设置的超时时间
            struct timeval {
            long tv_sec; / seconds /
            long tv_usec; / microseconds /
            };NULL : 永久阻塞,直到检测到了文件描述符有变化
            ● tv_sec = 0 tv_usec = 0, 不阻塞
            ● tv_sec > 0 tv_usec > 0, 阻塞对应的时间
● 返回值 :-1 : 失败
    ● >0(n) : 检测的集合中有n个文件描述符发生了变化

// 将参数文件描述符fd对应的标志位设置为0
void FD_CLR(int fd, fd_set *set);
// 判断fd对应的标志位是0还是1, 返回值 : fd对应的标志位的值,0,返回0, 1,返回1
int FD_ISSET(int fd, fd_set *set);
// 将参数文件描述符fd 对应的标志位,设置为1
void FD_SET(int fd, fd_set *set);
// fd_set一共有1024 bit, 全部初始化为0
void FD_ZERO(fd_set *set);

image.png

poll
#include <poll.h>
struct pollfd {
    int fd; / 委托内核检测的文件描述符 /
    short events; / 委托内核检测文件描述符的什么事件 /
    short revents; / 文件描述符实际发生的事件 /
};

struct pollfd myfd;
myfd.fd = 5;
myfd.events = POLLIN | POLLOUT;

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
● 参数:
    ● fds : 是一个struct pollfd 结构体数组,这是一个需要检测的文件描述符的集合
    ● nfds : 这个是第一个参数数组中最后一个有效元素的下标 + 1
    ● timeout : 阻塞时长
        0 : 不阻塞
        -1 : 阻塞,当检测到需要检测的文件描述符有变化,解除阻塞  
        >0 : 阻塞的时长
● 返回值:
    -1 : 失败   
    >0(n) : 成功,n表示检测到集合中有n个文件描述符发生变化

image.png

epoll
#include <sys/epoll.h>
// 创建一个新的epoll实例。在内核中创建了一个数据,这个数据中有两个比较重要的数据,一个是需要检
测的文件描述符的信息(红黑树),还有一个是就绪列表,存放检测到数据发送改变的文件描述符信息(双向
链表)。
int epoll_create(int size);
    ● 参数:
        size : 目前没有意义了。随便写一个数,必须大于0
    ● 返回值:
        -1 : 失败       
        0 : 文件描述符,操作epoll实例的

typedef union epoll_data {
    void *ptr;
    int fd;
    uint32_t u32;
    uint64_t u64;
} epoll_data_t;

struct epoll_event {
    uint32_t events; / Epoll events /
    epoll_data_t data; / User data variable /
};

常见的Epoll检测事件:
    ● EPOLLIN
    ● EPOLLOUT
    ● EPOLLERR

// 对epoll实例进行管理:添加文件描述符信息,删除信息,修改信息
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
 参数:
    ● epfd : epoll实例对应的文件描述符
    ● op : 要进行什么操作
        EPOLL_CTL_ADD: 添加
        EPOLL_CTL_MOD: 修改
        EPOLL_CTL_DEL: 删除
    ● fd : 要检测的文件描述符
    ● event : 检测文件描述符什么事情

// 检测函数
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int
timeout);
● 参数:
    ● epfd : epoll实例对应的文件描述符
    ● events : 传出参数,保存了发送了变化的文件描述符的信息
    ● maxevents : 第二个参数结构体数组的大小
    ● timeout : 阻塞时间
        ● 0 : 不阻塞
        ● -1 : 阻塞,直到检测到fd数据发生变化,解除阻塞
        ● >0 : 阻塞的时长(毫秒)
● 返回值:
    ● 成功,返回发送变化的文件描述符的个数 > 0
    ● 失败 -1

Epoll 的工作模式:

LT 模式 (水平触发)
假设委托内核检测读事件 -> 检测fd的读缓冲区
    读缓冲区有数据 - > epoll检测到了会给用户通知
         a.用户不读数据,数据一直在缓冲区,epoll 会一直通知
         b.用户只读了一部分数据,epoll会通知
         c.缓冲区的数据读完了,不通知 

:::info
LT(level - triggered)是缺省的工作方式,并且同时支持 block 和 no-block socket。在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的 fd 进行 IO 操作。如果你不作任何操作,内核还是会继续通知你的。
:::

ET 模式(边沿触发)
假设委托内核检测读事件 -> 检测fd的读缓冲区
    读缓冲区有数据 - > epoll检测到了会给用户通知
        a.用户不读数据,数据一致在缓冲区中,epoll下次检测的时候就不通知了
        b.用户只读了一部分数据,epoll不通知
        c.缓冲区的数据读完了,不通知 

:::info
ET(edge - triggered)是高速工作方式,只支持 no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了。但是请注意,如果一直不对这个 fd 作 IO 操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once)。

ET 模式在很大程度上减少了 epoll 事件被重复触发的次数,因此效率要比 LT 模式高。epoll工作在 ET 模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死
:::

 struct epoll_event {
    uint32_t events; /* Epoll events */
    epoll_data_t data; /* User data variable */
};
常见的Epoll检测事件:
- EPOLLIN
- EPOLLOUT
- EPOLLERR
- EPOLLET 
UDP通信

image.png

#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
- 参数:
    - sockfd : 通信的fd
    - buf : 要发送的数据
    - len : 发送数据的长度
    - flags : 0
    - dest_addr : 通信的另外一端的地址信息
    - addrlen : 地址的内存大小
    
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
- 参数:
    - sockfd : 通信的fd
    - buf : 接收数据的数组
    - len : 数组的大小 
    - flags : 0
    - src_addr : 用来保存另外一端的地址信息,不需要可以指定为NULL
    - addrlen : 地址的内存大小 


广播

:::info
向子网中多台计算机发送消息,并且子网中所有的计算机都可以接收到发送方发送的消息,每个广播消息都包含一个特殊的IP地址,这个IP中子网内主机标志部分的二进制全部为1。
a.只能在局域网中使用。
b.客户端需要绑定服务器广播使用的端口,才可以接收到广播消息。
:::
image.png

// 设置广播属性的函数
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t
optlen);
- sockfd : 文件描述符
- level : SOL_SOCKET
- optname : SO_BROADCAST
- optval : int类型的值,为1表示允许广播
- optlen : optval的大小 
 
组播(多播)

:::info

单播地址标识单个 IP 接口,广播地址标识某个子网的所有 IP 接口,多播地址标识一组 IP 接口。

单播和广播是寻址方案的两个极端(要么单个要么全部),多播则意在两者之间提供一种折中方案。多播数据报只应该由对它感兴趣的接口接收,也就是说由运行相应多播会话应用系统的主机上的接口接收。另外,广播一般局限于局域网内使用,而多播则既可以用于局域网,也可以跨广域网使用。
a.组播既可以用于局域网,也可以用于广域网
b.客户端需要加入多播组,才能接收到多播的数据

:::
image.png

组播地址

:::info

IP 多播通信必须依赖于 IP 多播地址,在 IPv4 中它的范围从 224.0.0.0 到 239.255.255.255 ,

并被划分为局部链接多播地址、预留多播地址和管理权限多播地址三类:
:::
image.png

设置组播

 int setsockopt(int sockfd, int level, int optname,const void *optval,socklen_t optlen);
 //服务器设置多播的信息,外出接口 
     - level : IPPROTO_IP
    - optname : IP_MULTICAST_IF
    - optval : struct in_addr
 //客户端加入到多播组:
    - level : IPPROTO_IP
    - optname : IP_ADD_MEMBERSHIP
    - optval : struct ip_mreq

struct ip_mreq{
/* IP multicast address of group. 	*/
struct in_addr imr_multiaddr; 	// 组播的IP地址

/* Local IP address of interface. 	*/
struct in_addr imr_interface; 	// 本地的IP地址
};

typedef uint32_t in_addr_t;
struct in_addr{
  in_addr_t s_addr;
}; 
 
本地套接字

:::info
本地套接字的作用:本地的进程间通信
有关系的进程间的通信
没有关系的进程间的通信
本地套接字实现流程和网络套接字类似,一般采用TCP的通信流程。
:::
image.png

//本地套接字通信的流程 - tcp
// 服务器端
1. 创建监听的套接字
int lfd = socket(AF_UNIX/AF_LOCAL, SOCK_STREAM, 0);
2. 监听的套接字绑定本地的套接字文件 -> server端
struct sockaddr_un addr;
// 绑定成功之后,指定的sun_path中的套接字文件会自动生成。
bind(lfd, addr, len);
3. 监听
listen(lfd, 100);
4. 等待并接受连接请求
struct sockaddr_un cliaddr;
int cfd = accept(lfd, &cliaddr, len);
5. 通信
接收数据:read/recv
发送数据:write/send
6. 关闭连接
close();

// 客户端的流程
1. 创建通信的套接字
int fd = socket(AF_UNIX/AF_LOCAL, SOCK_STREAM, 0);
2. 监听的套接字绑定本地的IP 端口
struct sockaddr_un addr;
// 绑定成功之后,指定的sun_path中的套接字文件会自动生成。
bind(lfd, addr, len);
3. 连接服务器
struct sockaddr_un serveraddr;
connect(fd, &serveraddr, sizeof(serveraddr));
4. 通信
接收数据:read/recv
发送数据:write/send
5. 关闭连接
close(); 
 
// 头文件: sys/un.h
#define UNIX_PATH_MAX 108
struct sockaddr_un {
    sa_family_t sun_family; // 地址族协议 af_local
    char sun_path[UNIX_PATH_MAX]; // 套接字文件的路径, 这是一个伪文件, 大小永远=0
}; 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值