Linux网络编程学习笔记

第7章 套接字基础

套接字地址结构

struct sockaddr{···};
struct sockaddr_in{···};
在这里插入图片描述

创建网络插口函数socket()

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

描述:协议族domain、协议类型type、协议编号protocol;
返回值:成功返回套接字文件描述符,失败返回-1
例子:
int sock = socket(AF_INET, SOCK_STREAM, 0);

绑定一个地址端口对函数bind()

作用:将一个套接字文件描述符与一个本地地址进行绑定,即指定数据的端口地址和IP地址
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen); //prototype
描述:函数将长度为addrlen的my_addr结构与sockfd绑定在一起
sockfd为socket()函数创建的文件描述符;
my_addr为指向sockaddr结构类型的指针,须先设置好my_addr的数据再进行绑定
addrlen为my_addr结构的长度,一般为sizeof(struct sockaddr)。

返回值: 0成功,-1失败

监听本地端口listen()

服务器模式接受一个连接前,用listen()侦听端口,初始化可连接队列,将多个客户端请求放在等待队列中。
int listen(int sockfd, int backlog); //prototype
描述:
backlog:等待队列的长度
返回值:0成功,-1失败

接受一个网络请求accept()

为阻塞式函数
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
描述:通过addr参数获得成功连接客户端的IP、端口和协议族信息;
返回值:成功返回新连接客户端套接字文件描述符,失败返回-1

连接目标网络服务器connect()

客户端在建立套接字之后,不需要进行地址绑定就可以直接连接服务器。
int connect(int sockfd, struct sockaddr* serv_addr, int addrlen);
描述:连接指定参数的服务器,例如IP、端口。
serv_addr包含需要连接的服务器目的端口、IP和协议类型
返回值:0成功,-1失败

写入数据函数write()

当服务器端收到一个客户端的连接后,可以通过套接字描述符进行数据的写入。
int write(int sockfd, datatype* data, int datalen); //prototype
返回值:成功写入的数据长度

int size;
char data[1024];
size = write(sockfd, data, 1024);   //将1024长度的data写入sockfd

读取数据函数read()

int read(int sockfd, datatype* buffer, int readlen);
描述:从sockfd中读取readlen长度的数据放入缓存区buffer中

注:使用write()和read()函数时,sockfd为0表示标准输入,1表示标准输出。

关闭套接字函数close() / shutdown()

关闭已经打开的socket连接,释放相关的资源,不能再使用该套接字文件描述符sockfd进行读写操作。
int shutdown(int sockfd, int how);
描述:how表示切断的方式(0,1,2)
返回值:0成功,-1失败
在这里插入图片描述

信号

信号将事件发送给相关的进程,相关进程可以对信号进行捕捉和处理。捕捉由系统自动完成,处理通过函数signal()完成。
信号SIGPIPE:例如当服务器已经关闭,而客户端还试图向套接字写入数据时会产生SIGPIPE信号。
信号SIGINT: 终止进程事件产生SIGINT信号,用于终止进程运行。

第8章 服务器和客户端信息的获取

字节序

概念:字节序是由于不同的处理器和操作系统,对大于一个字节的变量在内存中存放的顺序不同产生的。
小端字节序:变量内存地址的起始地址存放低位字节,高位字节顺序存放。
大端字节序:变量内存地址的起始地址存放高位字节,低位字节顺序存放。

字节序转换函数

#include<arpa/inet.h>
uint32_t htonl(uint32_t hostlong);  //主机字节序到网络字节序的long转换
uint16_t ntohs(uint16_t netshort);  //网络字节序到主机字节序的short转换

字符串IP地址和二进制IP地址的转换

Linux中的inet_xxx()函数

inet_pton()inet_ntop()函数
int inet_pton(int af, const char* src, void* dst); //将字符串类型IP地址转换成二进制类型
描述:
af为网络类型协议族,IPv4下为AF_INET;
src为需要转换的字符串;
dst指向转换后的结果;
返回值:成功返回正值,失败返回-1,0

const char* inet_ntop(int af, const void* src, char* dst, socket_t cnt); //将二进制IP地址转换成字符串类型
返回值:返回一个指向dst的指针

套接字描述符判定函数issockettype()

判定一个文件描述符是否是套接字描述符
int issockettype(int fd);

IP地址与域名之间的相互转换

DNS域名系统,树形结构,按照区域组成层次性结构。
获取主机信息的函数: gethostbyname() 和 gethostbyaddr()
struct hostinfo* gethostbyname(const char* name); //prototype
struct hostinfo* gethostbyaddr(const void* addr, int len, int type); //type为IP地址类型
不推荐使用代替函数getnameinfo()getaddrinfo()

协议名称处理函数xxxprotoxxx()

获取协议的名称和值

第9章 数据的IO和复用

网络数据的接收和发送有多种方案,例如直接收发、向量收发、消息收发。

IO函数(阻塞型)

直接收发:recv()接收数据
ssize_t recv(int sockfd, void* buf, size_t len, int flags);
描述:从套接字sockfd中接收数据,放到长度为len的缓冲区buf中,flags为接收方式。
返回值:成功时返回接收到的字节数,失败时返回-1

send()发送数据
ssize_t send(int sockfd, const void* buf, size_t len, int flags);
描述:将缓冲区buf中长度为len的数据,通过套接字描述符sockfd发送出去,flags为发送方式。
返回值:成功时返回已发送字节数,失败返回-1

向量收发:readv()接收数据
ssize_t readv(int sockfd, const struct iovec* vector, int count);
描述:可用于接收多个缓冲区数据。从套接字描述符sockfd中读取count块数据放入到缓冲区向量vector中。

writev()发送数据
ssize_t writev(int sockfd, const struct iovec* vector, int count);
描述:向sockfd中写入在vector中的count块数据。

消息收发:recvmsg()接收数据
ssize_t recvmsg(int s, struct msghdr* msg, int flags);

sendmsg()发送数据
ssize_t sendmsg(int s, struct msghdr* msg, int flags);
在这里插入图片描述

IO模型

阻塞IO、非阻塞IO模型、IO复用、信号驱动、异步IO
阻塞IO模型: 数据接收时,在数据没有到来之前会一直等待
非阻塞IO模型: 对于每次请求,内核都不会阻塞,会立即返回
IO复用: 在等待的时候加入超时的时间,未到超时时间阻塞,超时后仍没有数据到达则系统返回,不再等待。

信号驱动IO模型: 进程开始时注册信号处理回调函数,进程继续执行,信号发生时即IO数据到来,回调函数用recvmsg()接收数据。
异步IO模型: 与信号驱动类似,区别在于异步IO在数据复制完成再发送信号给回调函数。

select() 和 pselect()函数

用于IO复用,监视多个文件描述符的集合,判断是否有符合条件的事件发生。
int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);
描述:select()函数先对文件描述符进行查询,是否可读、写或者错误操作,当文件描述符满足条件时才进行操作。超时轮询的方式查看文件的读写错误可操作性。
在这里插入图片描述

int pselect(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timespec* timeout, const sigset_t* sigmask);
描述:Linux下与select()相似的函数,替换了信号处理方式,当sigmask为NULL时,与select方式一致。
pselect()的timeout为纳秒级分辨率,但是Linux内核调度为毫秒级

poll() 和 ppoll()函数

int poll(struct pollfd* fds, nfds_t nfds, int timeout); //等待某个文件描述符上的某个事件的发生
描述: 监视在fds数组指明的一组文件描述符上发生的动作,当满足条件或者超时即退出。

int ppoll(struct pollfd* fds, nfds_t nfds, const struct timespec* timeout, const sigset_t* sigmask);
描述:timeout采用纳秒级的变量,可在ppoll()函数处理中挂接临时的信号掩码。

非阻塞编程

fcntl(s, F_SETFL, O_NONBLOCK);
描述:使用F_SETFL命令将套接字s设置为非阻塞方式,再进行读写就能马上返回

第10章 基于UDP协议的接收和发送

UDP框架

缺少了connect(), listen(), accept()函数,因为UDP协议的无连接特性。
套接字类型:数据报套接字SOCK_DGRAM
在这里插入图片描述

出现的问题

问题一: UDP报文丢失,导致接收函数recv()/recvfrom()一直被阻塞。
解决办法:对数据报文进行反馈和重发。
问题二: 数据发送和接收的乱序。
解决:加入数据报序号。
问题三: 发送网络接口的绑定–>connect()

第11章 高级套接字

主要内容:UNIX编程、广播和多播概念及例子

UNIX域函数

UNIX域的协议族是在同一台主机上的客户/服务端通信的方法。
两种套接字:字节流套接字和数据报套接字,类似TCP/UDP。
在这里插入图片描述

广播

广播地址和端口接收端角度的广播接收地址和端口
广播用于一个主机对整个局域网所有主机上的通信。
例子:发现局域网上服务器的IP地址,服务器/客户端自动发现。

多播

多播地址和端口接收端通过自己的这个地址和端口进行接收
单播和广播为两个极端,多播对一组特定的主机进行通信。
setsockopt()getsockopt()函数实现,多播的选项为IP层的。
例子:一个多播的服务器端,建立一个数据报套接字,选定多播的IP的端口,直接向多播地址发送数据即可。
客户端只有加入多播组才能接收多播组的数据,将套接字绑定多播地址和端口。

第12章 套接字选项

主要内容:套接字选项、ioctl()函数有关请求命令、fcntl()函数有关请求命令。

获取和设置套接字getsocketopt() / setsocketopt()

int getsocketopt(int s, int level, int optname, void* optval, socklen_t* optlen);
int setsocketopt(int s, int level, int optname, void* optval, socklen_t* optlen);
在这里插入图片描述
参数level:
通用套接字为SOL_SOCKET
IP选项为IPPROTO_IP
TCP选项为IPPROTO_TCP
都对应有很多不同的选项optname

使用套接字选项

设置和获取缓冲区大小、获取套接字类型等等···

ioctl()函数

Linux下与内核交互的一种方法,网络程序设计中使用与内核中的网络协议栈进行交互。
int ioctl(int d, int request, ...); //多种参数

fcntl()函数

对套接字和通用描述符进行操作
int fcntl(int fd, int cmd, void arg);
例如对设置套接字为非阻塞IO

第13章 原始套接字

标准套接字:流式套接字、数据报套接字
原始套接字

第14章 服务器模型选择

循环服务器(串行服务器)

简单并发服务器

服务端,主程序提前构建多个子进程,当客户端请求到来时,系统从进程池中选取一个子进程处理客户端的请求,每个进程处理一个客户端请求
在这里插入图片描述
在这里插入图片描述

TCP高级并发服务器模型

按照accept()分类的多进程和多线程并发服务器

单客户端单进程,统一accept()

主进程统一处理客户端连接,客户端连接到来时才临时fork()进程。
在这里插入图片描述
在这里插入图片描述

单客户端单线程,统一accept()

在这里插入图片描述
在这里插入图片描述

单客户端单线程,各线程独自accept(),使用互斥锁

预先分配线程,创建线程池
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值