关键词:
前言:前面一篇文章手把手写C++服务器(21):Linux socket网络编程入门基础,讲解了如何建立socket连接、如何转换/使用socket地址、如何绑定/监听/发起/接受/断开/终止/关闭连接。socket博大精深,进阶会多写几弹,这一讲主要熟悉如何TCP、UDP读写以及通用数据读写,如何操作网络地址,socket选项设置等,进一步熟悉linux网络编程。
目录
地址信息函数:getsockname()、getpeername()
获取服务完整信息: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; // 服务类型
;
参考
- https://wizardforcel.gitbooks.io/linux-c-api-ref/content/282.html
- http://www.steves-internet-guide.com/tcpip-ports-sockets/
- 《linux高性能服务器编程》
- https://www.cnblogs.com/wanpengcoder/p/11749287.html
- https://blog.csdn.net/u010020404/article/details/78918937
- https://mp.weixin.qq.com/s/EyQ_RVJcDXgGkCBC-eEkQQ
- https://pubs.opengroup.org/onlinepubs/7908799/xns/getsockopt.html
手把手写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重定位标准输出... 查看详情
手把手写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、阻塞模... 查看详情