手把手写c++服务器(22):linuxsocket网络编程进阶第一弹(代码片段)

沉迷单车的追风少年 沉迷单车的追风少年     2022-12-19     706

关键词:

前言:前面一篇文章手把手写C++服务器(21):Linux socket网络编程入门基础,讲解了如何建立socket连接、如何转换/使用socket地址、如何绑定/监听/发起/接受/断开/终止/关闭连接。socket博大精深,进阶会多写几弹,这一讲主要熟悉如何TCP、UDP读写以及通用数据读写,如何操作网络地址,socket选项设置等,进一步熟悉linux网络编程。

目录

TCP数据读写:recv()、send()

UDP数据读写:recvfrom()、sendto()

通用数据读写:recvmsg()、sendmsg()

地址信息函数:getsockname()、getpeername()

socket选项

常用选项选讲:

获取服务完整信息:getserverbyname()、getserverbyport()

参考


TCP数据读写:recv()、send()

TCP是流协议,recv()和send()用于读写缓冲区:

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

recv读取sockfd上的数据, buf和len参数分别指定读缓冲区的位置和大小, flags参数通常设置为0即可。

recv成功时返回实际读取到的数据的长度, 它可能小于我们期望的长度len。 因此我们可能要多次调用recv, 才能读取到完整的数据

send往sockfd上写入数据, buf和len参数分别指定写缓冲区的位置和大小。 send成功时返回实际写入的数据的长度, 失败则返回-1并设置errno。

flags参数:一般设0,其他数值定义如下 MSG_OOB 传送的数据以out-of-band 送出。 MSG_DONTROUTE 取消路由表查询 MSG_DONTWAIT 设置为不可阻断运作 MSG_NOSIGNAL 此动作不愿被SIGPIPE 信号中断。

UDP数据读写:recvfrom()、sendto()

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, int void* buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addrlen);
ssize_t sendto(int sockfd, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);

recvfrom:用于读取sockfd上面的数据;

sendto:往sockfd上写入数据;

buf:缓冲区的位置

len:缓冲区大小

相比于tcp的两个API recv()和send(),参数多了地址src_addr和地址的长度addrlen,这是因为UDP没有连接的概念,每次读取数据都需要获取发送端的socket地址。

通用数据读写:recvmsg()、sendmsg()

通用的意思是TCP和UDP都能使用

#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags);
ssize_r sendmsg(int sockfd, struct msghdr* msg, int flags);

msghdr结构的定义:

#include<sys/socket.h>
struct msghdr   
    void  * msg_name ;   / *  消息的协议地址  * / 协议地址和套接口信息,在非连接的UDP中,发送者要指定对方地址端口,接受方用于的到数据来源,如果不需要的话可以设置为NULL(在TCP或者连接的UDP中,一般设置为NULL)
    socklen_t msg_namelen ;   / *  地址的长度  * / 
    struct iovec  * msg_iov ;   / *  多io缓冲区的地址  * / 
     int  msg_iovlen ;   / *  缓冲区的个数  * / 
    void  * msg_control ;   / *  辅助数据的地址  * / 
    socklen_t msg_controllen ;   / *  辅助数据的长度  * / 
     int  msg_flags ;   / *  接收消息的标识  * / 
 ;

地址信息函数:getsockname()、getpeername()

#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr* address, socklen_t* address_len);
int getpeername(int sockfd, struct sockaddr* address, socklen_t* address_len);

getsockname():获取sockfd对应的本端socket地址,并将其存储与address参数指定内存中。如果实际socket地址长度大于address指定内存中的大小,那么该socket地址将被截断 。

getpeername():获取sockfd对应的远端socket地址,用法和getsockname类似。

socket选项

读取和设置文件描述符的属性和方法。

#include <sys/socket.h>
int getsockopt(int sockfd, int level, int option_name, void* option_value, socklen_t* restrict option_len);
int setsockopt(int sockfd, int level, int option_name, const void* option_value, socklen_t* restrict option_len);

level:指定属性,如IPv4、IPv6、TCP等

具体选项参数含义:https://pubs.opengroup.org/onlinepubs/7908799/xns/getsockopt.html

#define SOL_IP 0

#define SOL_IPX 256

#define SOL_AX25 257

#define SOL_ATALK 258

#define SOL_NETROM 259

#define SOL_TCP 6

#define SOL_UDP 17

#define SOL_SOCKET 0xffff

常用选项选讲:

1、SO_REUSEADDR

当TCP连接处于TIME_WAIT状态的时候,SO_REUSEADDR来强制使用被处于TIME_WAIT状态的连接占用的socket地址。使该地址能立即被重用。

2、SO_RCVBUF

TCP接收缓冲区大小

3、SO_SNDBUF

TCP发送缓冲区大小

4、SO_RCVLOWAT

TCP接收缓冲区低水位标记,被I/O复用系统调用用来判断socket是否可写。

5、SO_SNDLOWAT

TCP发送缓冲区低水位标记,被I/O复用系统调用用来判断socket是否可写。

6、SO_LINGER

控制close系统调用在关闭TCP连接时的行为

获取服务完整信息:getserverbyname()、getserverbyport()

#include <netdb.h>
struct servent* getserverbyname(const char* name, const char* proto);
struct servent* getserverbyport(int port, const char* proto);

getserverbyname:根据名称获取某个服务的完整信息。

getserverbyport:根据端口号获取某个服务的完整信息。

两个函数都是通过读取/etc/services文件来获取服务信息的。

参数name指定目标服务的名字;port指定端口号;proto指定服务类型,传递tcp表示获取流服务,传递udp表示获取数据报服务,传递NULL表示获取所有类型的服务。

返回servent结构体定义如下:

#include <netdb.h>
struct servent 
    char* s_name;    // 服务名称
    char** s_aliases;// 服务别名列表
    int s_port;      // 端口号
    char* s_proto;   // 服务类型
;

参考

手把手写c++服务器:专栏文章-汇总导航更新中

手把手写C++服务器(1):网络编程常见误区手把手写C++服务器(2):C/C++编译链接模型、函数重载隐患、头文件使用规范手把手写C++服务器(3):C++编译常见问题、编译优化方法、C++库发... 查看详情

手把手写c++服务器(26):常用i/o操作创建文件描述符

本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:通过上一篇文章(手把手写C++服务器(25):万物皆可文件之socketfd),Linux万物皆文件的一定深入人心。如何操作这些文件?I/O函数将震撼登场!第一... 查看详情

手把手写c++服务器(25):万物皆可文件之socketfd(代码片段)

 本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:大家一定听说过在Linux当中,万物皆是文件,任何客观的存在都是以文件形式呈现。前面讲socket编程的时候(手把手写C+&... 查看详情

手把手写c++服务器(33):linux常用命令合集

 本系列文章导航: 手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:服务端编程的过程当中,各种常用的命令行也会大量使用;熟悉常用Linux命令不仅仅是运维的基本要求,也是一个主程的基本门槛。这里... 查看详情

手把手写c++服务器(27):五大文件描述符零拷贝控制总结(代码片段)

 本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:前文《手把手写C++服务器(26):常用I/O操作、创建文件描述符》、《手把手写C++服务器(25):万物皆可文件之sock... 查看详情

手把手写c++服务器(28):手撕cgi通用网关接口服务器代码(代码片段)

 本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:前文《手把手写C++服务器(26):常用I/O操作、创建文件描述符》《手把手写C++服务器(27):五大文件描述符零拷... 查看详情

手把手写c++服务器(29):手撕echo回射服务器代码(代码片段)

 本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:上一讲《手把手写C++服务器(28):手撕CGI通用网关接口服务器代码》讲解了如何利用复制文件描述符dup重定位标准输出&#x... 查看详情

手把手写c++服务器(30):手撕代码——基于tcp/ip的抛弃服务discard(代码片段)

 本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:前面两讲讲了echo服务器和CGI网关服务器《手把手写C++服务器(29):手撕echo回射服务器代码》《手把手写C++服务器(2... 查看详情

手把手写c++服务器(32):三大事件之信号详解(代码片段)

本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:信号实际上是一种软中断,信号机制实际上是进程间通信的一种方式。状态改变、系统异常、系统状态的变化等等,这些是... 查看详情

手把手写c++服务器(31):服务器性能提升关键——io复用技术两万字长文

 本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:Linux中素有“万物皆文件,一切皆IO”的说法。前面几讲手撕了CGI网关服务器、echo回显服务器、discard服务的代码,但是这几个一次只能监听... 查看详情

手把手写c++服务器(21):linuxsocket网络编程入门基础(代码片段)

本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】前言:刚开始写C++服务器的时候,我们进行网络编程肯定是使用socketAPI,等熟练之后,会根据我们自己的需要,封装... 查看详情

手把手写c++服务器(23):必知必会!操作系统面试十连问

前言:系列文章手把手写C++服务器(17):自测!TCP协议面试经典十连问受到了大家的收藏和点赞,谢谢读者的支持。操作系统是后端开发工程师的童子功,掌握常见的操作系统基础知识不仅有助于我们日... 查看详情

手把手写c++服务器(34):高并发高吞吐io秘密武器——epoll池化技术两万字长文(代码片段)

本系列文章导航: 手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:前文手把手写C++服务器(31):服务器性能提升关键——IO复用技术【两万字长文】介绍了IO复用技术,其中重点比较了... 查看详情

手把手写c++服务器(17):自测!tcp协议面试经典十连问(代码片段)

前言:前面一篇文章《手把手写C++服务器(15):网络编程入门第一个TCP项目》介绍了一个简单入门级的TCP项目,这一篇文章重点讲一讲面试常见的TCP协议相关的十个问题,都是后端开发程序员必知必会的经典... 查看详情

手把手写c++服务器(17):自测!tcp协议面试经典十连问(代码片段)

前言:前面一篇文章《手把手写C++服务器(15):网络编程入门第一个TCP项目》介绍了一个简单入门级的TCP项目,这一篇文章重点讲一讲面试常见的TCP协议相关的十个问题,都是后端开发程序员必知必会的经典... 查看详情

手把手写c++服务器(31):服务器性能提升关键——io复用技术两万字长文(代码片段)

 本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:Linux中素有“万物皆文件,一切皆IO”的说法。前面几讲手撕了CGI网关服务器、echo回显服务器、discard服务的代码,但是这... 查看详情

手把手写c++服务器(24):socket响应一般框架tcp修改缓冲区内核监听listen最大长度(代码片段)

本系列文章导航:手把手写C++服务器(0):专栏文章-汇总导航【更新中】 前言:本系列文章手把手写C++服务器(15):网络编程入门第一个TCP项目以封装好的网络库为例,重点讲解了如何正确的建立TCP... 查看详情

手把手写c++服务器(38):面试必背!linux网络socket编程必会十问!(代码片段)

 本系列文章导航: 手把手写C++服务器(0):专栏文章-汇总导航【更新中】目录1、说一下客户端和服务端socket建立连接和关闭连接的过程2、如何将一个socket设置成非阻塞模式3、什么是socket三大属性?4、阻塞模... 查看详情