设计网站轮廓模板,php源码建站 一品资源,wordpress qqoq主题,北京代理记账服务公司目录 一、网路套接字编程
#xff08;一#xff09;基础概念
1、源IP地址与目的IP地址
2、端口号
3、TCP与UDP
4、网络字节序
#xff08;二#xff09;套接字编程接口
1、socket 常见API
2、sockaddr结构
#xff08;三#xff09;UDP套接字
1、UDP服务器创建…目录 一、网路套接字编程
一基础概念
1、源IP地址与目的IP地址
2、端口号
3、TCP与UDP
4、网络字节序
二套接字编程接口
1、socket 常见API
2、sockaddr结构
三UDP套接字
1、UDP服务器创建流程
2、UDP客户端创建流程
3、创建 socket 套接字
4、绑定 socket 端口号
5、服务器客户端数据的发送与接收
四TCP套接字
1、TCP服务器创建流程
2、TCP客户端创建流程
3、创建 socket 套接字
4、绑定 socketI P地址与端口号
5、服务器设置监听状态
6、服务器获取客户端连接请求
7、客户端连接请求
二、守护进程
一概念
二函数接口
三模拟实现 一、网路套接字编程
一基础概念
1、源IP地址与目的IP地址 在网络中IP地址就是用来标识处于网络中的一台主机的地址而源IP地址就是发送主机的地址而目的IP地址就是接收主机的IP地址。
2、端口号 在网路通信中仅仅知道主机的地址是不够的。例如当我们打开QQ并发送一条消息时当接收主机收到该数据时是无法确定该数据是发给QQ的还是微信的。因此在网路通信中还需要 端口号。 端口号是传输层协议的内容。 端口号是一个2字节16位的整数端口号用于标识一台主机上的进程在网络通信中通过端口可以得知该数据一个交给哪一个进程IP地址 端口号 能够标识网络上的某一台主机的某一个进程一个端口号只能被一个进程占用但一个进程可以占用多个端口号。 网络通信的本质实际时进程间通信那为什么不直接使用进程 PID 来代替端口号呢 1使网络通信与操作系统解耦 2我们知道进程 PID 是由操作系统给出的当服务器重启后其PID很可能会发生改变如果直接使用 PID 作为标识不便于网络通信。 因此在网络通信中不仅有源IP地址和目的IP地址还有源端口号和目的端口号。除此之外操作系统内部维护了一张哈希表用于映射端口号到进程PCB的地址。
3、TCP与UDP TCP 传输控制协议 传输层协议有链接可靠传输面向字节流 UDP用户数据报协议 传输层协议无连接不可靠传输面向数据报 4、网络字节序 内存中的很多字节数据相对于内存地址有大端和小端之分磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分网络数据流同样有大端小端之分。 TCP/IP协议规定网络数据流应采用大端字节序即低地址高字节如果发送主机是小端字节序需先将数据转换为大端后发送如果发送主机是大端字节序则直接进行发送即可但在实际编程时考虑到代码移植性无论大端机还是小段机向网络发送数据还是从网络接收数据统一进行转换发送主机和接收主机都按照低地址到高地址发送接收数据 考虑到网络字节序的问题C语言为我们提供了库函数。
#include arpa/inet.h
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);以上便是字节序转换函数例如 htons() 表示将16位短整数从主机字节序转换到网络字节序至于具体是否需要进行转换由函数内部决定。 同样对于IP地址也需要进行转换。
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.h
int inet_aton(const char *cp, struct in_addr *inp);
//将点分十进制字符串转换为 uint32_t 的网络字节序
in_addr_t inet_addr(const char *cp);
in_addr_t inet_network(const char *cp);
//将32位的IPv4地址转化为点分十进制字符串
char *inet_ntoa(struct in_addr in);
struct in_addr inet_makeaddr(int net, int host);
in_addr_t inet_lnaof(struct in_addr in);
in_addr_t inet_netof(struct in_addr in);二套接字编程接口
1、socket 常见API
// 创建 socket 文件描述符 (TCP/UDP, 客户端 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address, socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
2、sockaddr结构 socket API是一层抽象的网络编程接口适用于各种底层网络协议如IPv4、IPv6等各种网络协议的地址格式并不相同。 在使用socket API时无论是网络套接字还是域间套接字都需要强转为 struct sockaddr 类型通过传入参数 socketaddr 的前16位操作系统可以分辨是哪种套接字从而在内部切换对应的套接字结构。
//sockaddr 结构
/* Structure describing a generic socket address. */
struct sockaddr{__SOCKADDR_COMMON (sa_); /* Common data: address family and length. */char sa_data[14]; /* Address data. */};//sockaddr_in 结构
/* Structure describing an Internet socket address. */
struct sockaddr_in{__SOCKADDR_COMMON (sin_);in_port_t sin_port; /* Port number. */struct in_addr sin_addr; /* Internet address. *//* Pad to size of struct sockaddr. */unsigned char sin_zero[sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)];};//in_addr结构
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr{in_addr_t s_addr;};
三UDP套接字
1、UDP服务器创建流程 1、创建套接字 2、绑定IP地址和端口号 3、接收数据、处理数据和发送数据。 2、UDP客户端创建流程 1、创建套接字 2、客户端不需要显式 bind IP地址与端口号该动作由操作系统完成 3、发送数据、接收数据和对数据进行处理。 3、创建 socket 套接字
NAMEsocket - create an endpoint for communication
SYNOPSIS#include sys/socket.hint socket(int domain, int type, int protocol);
RETURN VALUEUpon successful completion, socket() shall return a non-negative
integer, the socket file descriptor. Otherwise, a value of -1 shall be returned
and errno set to indicate the error.用途服务器与客户端创建 socket 文件描述符TCP/UDP 参数 domain指定套接字的协议族常见的协议族有AF_INETIPv4网络通信、AF_UNIX/AF_LOCAL本地通信type指定套接字的类型。常见的类型有SOCK_STREAM流套接字和SOCK_DGRAM数据报套接字。protocol套接字使用的具体协议通常与 domain和 type配合使用。一般情况下可以将其设置为 0表示由操作系统根据 domain和 type自动选择合适的协议。 返回值 如果成功会返回一个非负的整型值表示套接字的文件描述符如果失败返回-1并设置 error 来表示错误原因。 4、绑定 socket 端口号
NAMEbind - bind a name to a socket
SYNOPSIS#include sys/socket.hint bind(int socket, const struct sockaddr *address,socklen_t address_len);
RETURN VALUEUpon successful completion, bind() shall return 0; otherwise, -1 shall
be returned and errno set to indicate the error.用途将一个套接字与一个特定的IP地址和端口号绑定 参数 socket套接字的文件描述符address指向 struct sockaddr 类型的指针包含套接字将要绑定的地址信息。具体的地址结构根据协议族的不同而有所区别address_len地址结构的长度通常使用 sizeof 来获取。 5、服务器客户端数据的发送与接收
NAMEsendto - send a message on a socket
SYNOPSIS#include sys/socket.hssize_t sendto(int socket, const void *message, size_t length,int flags, const struct sockaddr *dest_addr,socklen_t dest_len);
RETURN VALUEUpon successful completion, sendto() shall return the number of bytes
sent. Otherwise, -1 shall be returned and errno set to indicate the error.用途从已连接的 socket 中发送数据常用于通过 UDP 协议或其他支持无连接的协议发送数据。 参数 socket套接字的文件描述符message发送数据的地址length发送数据的长度flags控制发送操作的标志通常为0dest_addr指向 sockaddr 结构体指针包含目标地址的信息dest_lendest_addr 的长度以字节为单位。 返回值 成功时返回发送的字节数失败时返回-1并设置错误码。 NAMErecvfrom - receive a message from a socket
SYNOPSIS#include sys/socket.hssize_t recvfrom(int socket, void *restrict buffer, size_t length,int flags, struct sockaddr *restrict address,socklen_t *restrict address_len);
RETURN VALUEUpon successful completion, recvfrom() shall return the length of the
message in bytes. If no messages are available to be received and the peer
has performed an orderly shutdown, recvfrom() shall return 0. Otherwise,
the function shall return -1 and set errno to indicate the error. 用途从套接字接收数据的函数它可以接收来自网络的消息并允许用户指定用于接收消息的缓冲区常用于 UDP 协议和其他无连接协议中。 参数 socket套接字的文件描述符buffer指向内存缓冲区的指针用于存储接收到的数据lengthbuffer缓冲区的大小flags控制接收操作的标志通常为 0address指向 sockaddr 结构体的指针接收端的信息由此填充address_len指向 address 结构体的指针表示该结构体的长度。 返回值 成功时返回接收到的字节数若无消息接收且接收方关闭连接则返回0失败时返回-1并设置错误码。 四TCP套接字
1、TCP服务器创建流程 1、创建套接字 2、绑定IP地址和端口号 3、设置 socket 处于监听状态 4、等待获取客户端连接请求 5、接收数据、处理数据和发送数据。 2、TCP客户端创建流程 1、创建套接字 2、客户端不需要显式 bind IP地址与端口号该动作由操作系统完成 3、向服务器发送连接请求 4、发送数据、接收数据和对数据进行处理。 3、创建 socket 套接字 同UDP但传入参数不同。
//UDP
udpFd socket(AF_INET, SOCK_DGRAM, 0);
//TCP
tcpFd spcket(AF_INET, SOCK_STREAM, 0);
4、绑定 socketI P地址与端口号 同UDP但传入参数不同。
5、服务器设置监听状态
NAMElisten - listen for socket connections and limit the queue of incoming
connections
SYNOPSIS#include sys/socket.hint listen(int socket, int backlog);
RETURN VALUEUpon successful completions, listen() shall return 0; otherwise, -1
shall be returned and errno set to indicate the error. 用途在一个套接字上监听来自客户端的连接请求主要用于面向连接的协议如 TCP。 参数 socket套接字的文件描述符blcklog表示在套接字上等待连接的最大队列长度。 返回值 成功时返回0失败时返回-1并设置错误码。 6、服务器获取客户端连接请求
NAMEaccept - accept a new connection on a socket
SYNOPSIS#include sys/socket.hint accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);
RETURN VALUEUpon successful completion, accept() shall return the non-negative
file descriptor of the accepted socket. Otherwise, -1 shall be returned and
errno set to indicate the error. 用途在一个已监听的套接字上接受一个客户端的连接请求。 参数 socket套接字的文件描述符address指向 sockaddr 结构体的指针用来存储客户端的地址信息 address_len指向 socket_t 类型的指针表示 address 缓冲区的长度。 返回值 成功时返回一个新的套接字该文件描述符用于与用户进行数据交换失败时返回-1并设置错误码。 7、客户端连接请求
NAMEconnect - connect a socket
SYNOPSIS#include sys/socket.hint connect(int socket, const struct sockaddr *address,socklen_t address_len);
RETURN VALUEUpon successful completion, connect() shall return 0; otherwise, -1
shall be returned and errno set to indicate the error. 用途用于客户端向服务器发起连接请求。 参数 socket套接字的文件描述符address指向 sockaddr 结构体的指针结构体中包含了目标主机的 IP 地址和端口号等信息address_len表示结构体 address 的长度。 返回值 成功时返回0失败时返回-1并设置错误码。 二、守护进程
一概念 当我们登录云服务器并使服务器运行时如果我们退出登录云服务器上部署的服务器也会被关闭如何使得部署的服务器不受用户登录注销的影响呢 这时候就需要将服务器变为守护进程守护进程的本质实际是一个孤儿进程。 当我们登录云服务器时会建立一个会话一个会话只有一个前台进程和n个后台进程作业之间可以前后台转换但这些任务仍有可能收到用户登陆注销的影响。 而守护进程则是将目标进程独立出去成为一个新的会话因此便不受用户的影响可以一直运行下去。 其中SID则为会话IDPGID为一个进程组的ID该ID值与进程组组长的PID相同。
二函数接口 Linux生成守护进程的接口
NAMEdaemon - run in the background
SYNOPSIS#include unistd.hint daemon(int nochdir, int noclose);Feature Test Macro Requirements for glibc (see feature_test_macros(7)):daemon(): _BSD_SOURCE || (_XOPEN_SOURCE _XOPEN_SOURCE 500)
RETURN VALUE(This function forks, and if the fork(2) succeeds, the parent
calls _exit(2), so that further errors are seen by the child only.) On
success daemon() returns zero. If an error occurs, daemon() returns -1
and sets errno to any of the errors specified for the fork(2) and setsid(2).用途将程序放到后台运行的函数通常在编写守护进程daemon process时使用。 参数 nochdir如果这个参数为非零值表示守护进程在后台运行时不会改变当前工作目录如果设置为 0则守护进程会将当前工作目录更改为根目录 /通常为了避免守护进程锁定在某个目录中导致无法卸载该目录noclose如果该参数为非零值表示守护进程不会关闭标准输入、标准输出和标准错误输出文件描述符即不调用 close()。如果设置为 0守护进程会关闭这些文件描述符。通常为了避免守护进程继承父进程的终端输出会关闭这些文件描述符。 返回值 成功时返回0失败时返回-1并设置错误码。 三模拟实现 在实现之前需知道一个函数
NAMEsetsid - create session and set process group ID
SYNOPSIS#include unistd.hpid_t setsid(void);
RETURN VALUEUpon successful completion, setsid() shall return the value of the
new process group ID of the calling process. Otherwise, it shall return
(pid_t)-1 and set errno to indicate the error.用途创建一个新的会话session并使当前进程成为新的会话领导进程并且不会收到终端的控制。进程组的组长不能调用setsid()函数来创建一个新的会话。 参数无 返回值 成功时返回该会话的ID失败时返回-1并设置错误码 #include iostream
#include signal.h
#include unistd.h
#include cassert
#include sys/types.h
#include sys/stat.h
#include fcntl.h
using namespace std;
//数据黑洞向它写入的数据会被吃掉读取数据什么都读不到不会使进程退出
#define DEV /dev/null
void daemonSelf(const char *currPath nullptr)
{signal(SIGPIPE, SIG_IGN);//创建子进程 使子进程成为守护进程if (fork() 0)exit(0);pid_t id setsid();assert(id ! -1);int fd open(DEV, O_RDWR);if (fd 0){//创建成功重定向dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);}else{//创建失败手动关闭close(0);close(1);close(2);}if (currPath)chdir(currPath);
}