您的位置:首页 > 教育 > 锐评 > 网络运营者对外提供产品和服务_前端自我介绍面试技巧_长沙市网站制作_怎么做百度搜索排名

网络运营者对外提供产品和服务_前端自我介绍面试技巧_长沙市网站制作_怎么做百度搜索排名

2025/1/8 4:55:22 来源:https://blog.csdn.net/2301_80163789/article/details/144959509  浏览:    关键词:网络运营者对外提供产品和服务_前端自我介绍面试技巧_长沙市网站制作_怎么做百度搜索排名
网络运营者对外提供产品和服务_前端自我介绍面试技巧_长沙市网站制作_怎么做百度搜索排名

Linux Socket编程

在网络中,IP 标识了全网唯一的主机,port 标识了主机上唯一的进程。socket = IP + port ,所以 socket 编程(套接字编程),就是通过用户的提供 IP 和端口,调用 socket 接口进行网络连接的技术。我们所进行的网络编程,实际就是在应用层上自定义应用层协议,应用层的下一层是传输层,所以 socket 编程需要我们了解 UDP 和 TCP 的区别和作用。其他层的协议,并不在应用层上不会进行操作。

在进行网络连接时,我们会在 UDP 和 TCP 两种连接方式中进行选择。UDP 的特点是:无连接,不可靠,面向数据报,适用于简单的网络传输中;TCP 的特点是:有连接,可靠,面向字节流,适用于需要保持稳定连接的网络传输中。

UDP 就像是赛博送信,信什么时候送到,以及能不能送到,UDP 都不关心。而 TCP 则相当于电话聊天,我们会先询问对方是否在听,再进行电话交流,最后还有告诉对方我要挂了(即 TCP 的三次握手和四次挥手)。

注意 UDP 不会对数据进行分包,也就是要传输一个特别大的文件时,适用 UDP 会导致超过 UDP 传输上限的后续内容全部丢失。如果非得适用 UDP 进行大文件传输,需要在应用层自定义 UDP 分包合包协议。

1. 网络编程常见API

1.1 socket常见API

#include <sys/types.h>

#include <sys/socket.h>

创建socket文件描述符(TCP/UDP,客户端+服务器)

int socket(int domain, int type, int protocol)

domain:表示参数是一个域,需要输入预设好的宏变量。域的宏变量有很多,如果是 AF_UNIX 则用于本地通信;如果是 AF_INET则用于网络通信。

type:表示套接字的类型,需要输入预设好的宏变量。类型的宏变量也有很多,如 SOCK_DGRAM 表示无连接、不可靠、指定大小的通信类型。

protocol:表示指定协议,如果不想(不用)指定,可以设置为0。

return val:成功返回值是一个文件描述符。网卡也是一个文件,socket() 相当于打开了网卡的文件,网络通信是再向网卡进行IO。

绑定端口号(TCP/UDP,服务器)

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

bind()用于将一本地地址(*addr)与一套接口捆绑(sockfd),该函数须在connect()listen()调用前使用。

sockfd:填入 socket() 返回的文件描述符。

*addr:是指向 sockaddr_in 结构体或 sockaddr_un 结构体的指针。这两个结构体都需要提前实例化进行设置才能使用。

addrlen:表示 addr 结构的长度,可以用sizeof操作符获得。

开始监听socket(TCP,服务器)

int listen(int sockfd, int backlog)

listen()sockfd 设置为监听套接字,此后便可以用accept()接受连接。

sockfd:填入 socket()返回的文件描述符。

backlog:连接请求队列的最大长度(一般由2到4),用SOMAXCONN则为系统给出的最大值。

接收请求(TCP,服务器)

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

accept()相当于一个中转站, sockfd 将来自网络另一端的连接接收,accept的返回值才是为该链接提供服务的 fd 。如果 sockfd 无连接,accept() 将会阻塞等待,直到有链接。(注意 sockfd 必须是调用 listen() 之后的监听套接字)

return fd:返回值是一个文件描述符,是用于为用户提供网络IO服务的套接字。

建立连接(TCP,客户端)

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

connect()bind() 的作用相同,只是 connect() 在客户端中使用, bind() 在服务器中使用。

1.2 序列转换常用API

头文件 和 API:

#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);

这些函数将整型在主机字节序和网络字节序之间转换。h 表示 host ,n 表示 network ,l 表示 32 位长整数,s 表示 16 位短整数。

如果主机是小端字节序,这些函数将参数进行相应的大小端转换后返回。

如果主机是大端字节序,调用这些函数将不对参数做处理直接返回。


头文件:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

API:

int inet_aton(const char *cp, struct in_addr *inp)

char *inet_ntoa(struct in_addr in)

inet_ntoa() 将网络地址转换成“点分十进制”的字符串格式IP形式返回。

inet_ntoa() 返回了一个 char* ,显然在函数内部为我们申请了一块内存空间来保存 IP。man 手册上描述,返回值放到了静态存储区,不需要手动释放。重复调用(同一线程)会覆盖原来的内存空间。

int inet_pton(int af, const char *src, void *dst)

inet_pton() 能够将“点分十进制”字符串形式的IP传入,将其转为网络序列的4字节整数,这是一个方便且安全的转换接口。

*dst:传入 struct in_addr 的地址。

const char *inet_ntop(int af, const void *src,char *dst, socklen_t size)

inet_ntop() 能够将网络序列的4字节整数IP转为主机序列后再转为“点分十进制”字符串形式返回,这是一个方便且安全的转换接口。

*dst:传入 struct in_addr 的地址。

1.3 网络通信发送接收常用API

#include <sys/types.h>

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen)

recvfrom()用于接收远程主机经指定的socket传来的数据,并把数据传到由参数buf指向的内存空间。适用于未连接的套接字,一般用于UDP。

ssize_t:表示signed size_t类型,ssize_t数据类型用来表示可以被执行读写操作的数据块的大小。(ssize_t 相当于 long int,用这个名字为的是提高代码的自说明性)

len:为可接收数据的最大长度。

falgs:表示调用操作方式。一般设置为0。

socklen_t:socklen_t是一个大小必须为16位的数据结构。(socklen_t 相当于int ,用这个名字为的是提高代码的自说明性)

*addrlen:指向src_add的指针,在调用 recvfrom()之前应设置为src_add的长度,在调用之后将被设置为新接收到的地址的实际大小。

return val:成功返回接收到的字符数,返回0表示对方关闭连接,失败返回-1。

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

recv()适用于已连接的套接字,一般用于TCP。

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen)

sendto(),指向一指定目的地发送数据,用于发送未建立连接的UDP数据包 (参数为SOCK_DGRAM)。参数flags 一般设0。

其他说明略。

ssize_t send(int sockfd, const void *buf, size_t len, int flags)

send()用于TCP。

FILE *popen(const char *command, const char *type)

popen()通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。

*command:Linux命令

*type:即打开文件的方式,如果 type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到 command 的标准输入。

return val:成功返回一个管道的文件指针,失败返回NULL。

1.4 sockaddr结构

socket API 是一层抽象的网络编程接口,适用于各种底层网络协议,但各种网络协议的地址格式并不相同。于是就有了 sockaddr_in 结构体用于本地通信,sockeaddr_un结构体用于网络通信,但 socke API 没有各自为其设置不同的接口,而是使用指针作为参数,通过指针指向不同的结构体类型实现了多态。

Socket1

1.5 sockaddr_in

struct sockaddr_in 是一个在 C 和 C++ 中用于描述 IPv4 地址的结构体。这个结构体通常用于套接字编程中,表示一个 IPv4 地址和端口号。struct sockaddr_in 结构体的大小通常是 16 个字节,其中 sin_zero 的存在确保了与 sockaddr 结构体的对齐和大小一致性。

注意:为保证使用中不被随机值影响,sockaddr_in对象在定义后一般会使用memset()将内部随机值设置为0。

sockaddr_in有四个成员变量:

sin_family

sin_family指定了协议族,在sockaddr_in中只能被定义成 AF_INET(表示 IPv4 使用的地址族)

sin_port

sin_port用于存储端口号。sin_port以网络字节序存储(大端),所以在设置时需要将主机序列转为网络序列(使用htons()

sin_addr

sin_addr是一个结构体类型,其包含的 s_addr 成员表示32位IPv4地址,以网络字节序存储,使用 inet_addr()inet_pton() 直接存储IP即可。

sin.sin_addr.s_addr = inet_addr("192.168.1.1"); // 将字符串形式的IP地址转换为网络字节序并赋值
inet_pton(AF_INET, "192.168.1.1", &sin.sin_addr); // 使用 inet_pton() 函数

注意:将s_addr设置为INADDR_ANY表示进行任意IP地址绑定。 在使用云服务器时对其设置为INADDR_ANY才可在本地测试网络通信。

sin_zero

这个成员仅用于保证sockaddr_in的结构体大小为16位。

2. socket UDP编程和TCP编程

UDP

UDP的特点是无连接,不可靠,面向数据报。与TCP相比,UDP较简单。UDP的 socket 在创建时,要将 type 参数设置为 SOCK_DGRAM表示面向数据报,使用 recvfrom() 接收彼端传来的数据,使用 sendto() 向彼端发送数据。

Socket2

TCP

TCP的特点是有连接,可靠,面向字节流。与UDP相比,TCP较复杂。TCP的 socket 在创建时,要将 type 参数设置为 SOCK_STREAM 表示面向字节流,由于TCP有连接,套接字在使用前需要使用 listen() 将套接字设置为监听套接字,再使用 accept() 接收请求。在客户端,要使用 connect() 使客户端与服务器连接。使用 recv() 接收彼端的数据,使用 send() 向彼端发送数据。

Socket3

共同点

  1. 端口号的类型必须是 uint16_t,使用端口号前注意当前是网络序列还是主机序列,是否需要进行序列转换。
  2. UDP和TCP的服务器端的IP需要设置为 ADDR_ANY,表示随机IP地址,只需要确定端口号。而客户端则需要确定IP地址和端口号。
  3. UDP和TCP在外层创建的socket不需要显式的bind,但是一定要有自己的 IP 和 port,所以需要隐式的 bind,OS会使用自己的 IP 和随机的端口号,自动 bind socket。
  4. 网络编程中,通常 read() 返回值大于 0 认为是正常读取,为 0 认为是通信正常结束,小于 0 认为是出错。

3. windows作为client访问Linux

Windows没有 Linux 使用的那些系统标准库,要使用相同的函数,需要手动引入:

#include <WinSock2.h>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")	//这个和WinSock2.h是对应关系
#pragma warning(disable : 4996)		//用于屏蔽c语言接口不安全的报错

在Windows中,使用 ws2_32.lib的哪一个版本,也需要声明:

int main()
{WSADATA wsd;	//WSA是Windows Sockets API的缩写WSAStartup(MAKEWORD(2,2),&wsd);	//表示使用2.2版本的库return 0;
}

Windows中还对sockfd进行了封装:

SOCKET sockfd = socket(AF_INET,SOCK_DGRAM,0);	//SOCKET是套接字描述符,实际用int也能编过
closesocket(sockfd);	//关闭sockfd也有对应的函数

因为Windows没有一切皆文件的概念,所以套接字会有一个描述符类型

在使用完创建的套接字后,还需要对加载的库资源进行清理:

WSACleanup();

4. 开发端口

测试程序:TCPdemo

测试工具:Windows cmd

命令:telnet [ip] [port]

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com