【应用】06.Socket编程
【嵌入式八股】一、语言篇https://www.nowcoder.com/creation/manager/columnDetail/mwQPeM
【嵌入式八股】二、计算机基础篇https://www.nowcoder.com/creation/manager/columnDetail/Mg5Lym
【嵌入式八股】三、硬件篇https://www.nowcoder.com/creation/manager/columnDetail/MRVDlM
【嵌入式八股】四、嵌入式Linux篇(本专栏)https://www.nowcoder.com/creation/manager/columnDetail/MQ2bb0
三、Linux网络编程
结合计算机网络学习
Socket编程
96.网络编程的作用?
Linux网络编程主要用于在Linux系统中进行网络通信(进行进程间通信,但这些进程是分布在不同主机上的进程)。它提供了一组丰富的网络编程接口和协议,使得开发者可以方便地开发基于网络的应用程序,如网络服务器、客户端、通信软件等。
Linux网络编程的主要作用包括:
- 提供底层的网络编程接口,如套接字(socket)、网络地址等,使得应用程序可以通过这些接口进行网络通信。
- 提供一系列网络协议的实现,如TCP、UDP、IP等,使得应用程序可以选择合适的协议进行网络通信。
- 提供网络编程相关的系统调用和函数,如
select()
、poll()
、epoll()
等,使得应用程序可以进行异步、非阻塞的网络通信操作。 - 提供一些网络编程相关的库,如libpcap、libcurl等,使得应用程序可以更方便地进行网络数据抓包、HTTP请求等操作。
97.网络应用程序设计模式
C/S模式
传统的网络应用设计模式,客户机(client)/服务器(server)模式。需要在通讯两端各自部署客户机和服务器来完成数据通信。
B/S模式
浏览器()/服务器(server)模式。只需在一端部署服务器,而另外一端使用每台PC都默认配置的浏览器即可完成数据的传输。
优缺点
对于C/S模式来说,其优点明显。客户端位于目标主机上可以保证性能,将数据缓存至客户端本地,从而提高数据传输效率。且,一般来说客户端和服务器程序由一个开发团队创作,所以他们之间所采用的协议相对灵活。可以在标准协议的基础上根据需求裁剪及定制。例如,腾讯公司所采用的通信协议,即为ftp协议的修改剪裁版。
因此,传统的网络应用程序及较大型的网络应用程序都首选C/S模式进行开发。如,知名的网络游戏魔兽世界。3D画面,数据量庞大,使用C/S模式可以提前在本地进行大量数据的缓存处理,从而提高观感。
C/S模式的缺点也较突出。由于客户端和服务器都需要有一个开发团队来完成开发。工作量将成倍提升,开发周期较长。另外,从用户角度出发,需要将客户端安插至用户主机上,对用户主机的安全性构成威胁。这也是很多用户不愿使用C/S模式应用程序的重要原因。
B/S模式相比C/S模式而言,由于它没有独立的客户端,使用标准浏览器作为客户端,其工作开发量较小。只需开发服务器端即可。另外由于其采用浏览器显示数据,因此移植性非常好,不受平台限制。如早期的偷菜游戏,在各个平台上都可以完美运行。
B/S模式的缺点也较明显。由于使用第三方浏览器,因此网络应用支持受限。另外,没有客户端放到对方主机上,缓存数据不尽如人意,从而传输数据量受到限制。应用的观感大打折扣。第三,必须与浏览器一样,采用标准http协议进行通信,协议选择不灵活。
因此在开发过程中,模式的选择由上述各自的特点决定。根据实际需求选择应用程序设计模式。
98.网络字节序
在 Linux 网络编程中,网络字节序是指在网络上传输时使用的字节序,它是一种规范的字节序,确保不同计算机之间的数据传输的正确性。
在计算机内部,数据的表示可以使用两种字节序,即大端字节序和小端字节序。大端字节序是指数据的高位字节存放在内存的低地址中,而小端字节序是指数据的低位字节存放在内存的低地址中。
为了在网络上传输时保证数据的正确性,所有计算机都必须使用相同的字节序。在网络编程中,网络字节序被规定为大端字节序,无论计算机的实际字节序是大端还是小端,都必须将数据转换为网络字节序后再进行传输。
在 Linux 网络编程中,可以使用一些函数来进行字节序的转换,如htonl()、htons()、ntohl() 和 ntohs(),它们分别表示将一个 32 位整数从主机字节序转换为网络字节序、将一个 16 位整数从主机字节序转换为网络字节序、将一个 32 位整数从网络字节序转换为主机字节序、将一个 16 位整数从网络字节序转换为主机字节序。
99.IP地址转换函数
IP地址转换函数的作用是将IP地址在二进制格式和文本格式之间进行转换。在计算机网络通信中,IP地址是网络通信中最重要的元素之一。在实际通信中,IP地址以文本格式(如IPv4地址中的“192.168.0.1”)或二进制格式(如IPv4地址中的32位二进制数)存在。为了方便处理和显示IP地址,需要在文本格式和二进制格式之间进行转换。
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
应用代码如下:
#include <stdio.h>
#include <arpa/inet.h> // 包含inet_pton()和inet_ntop()函数
int main() {
// IPv4地址转换示例
const char* ipv4_str = "192.168.0.1";
struct in_addr ipv4_addr;
inet_pton(AF_INET, ipv4_str, &ipv4_addr); // 将IPv4字符串转换为二进制格式
char ipv4_str2[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ipv4_addr, ipv4_str2, INET_ADDRSTRLEN); // 将IPv4二进制格式转换为字符串
printf("%s\n", ipv4_str2); // 输出:192.168.0.1
// IPv6地址转换示例
const char* ipv6_str = "fe80::2c16:eff:fe93:6b8c";
struct in6_addr ipv6_addr;
inet_pton(AF_INET6, ipv6_str, &ipv6_addr); // 将IPv6字符串转换为二进制格式
char ipv6_str2[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ipv6_addr, ipv6_str2, INET6_ADDRSTRLEN); // 将IPv6二进制格式转换为字符串
printf("%s\n", ipv6_str2); // 输出:fe80::2c16:eff:fe93:6b8c
return 0;
}
其中,inet_pton()
函数将IP地址字符串转换为二进制格式,需要指定地址族参数,可以使用AF_INET
表示IPv4地址族,AF_INET6
表示IPv6地址族。inet_ntop()
函数将IP地址的二进制格式转换为字符串格式,同样需要指定地址族参数。在调用inet_ntop()
函数时,需要提供一个指向存储字符串的缓冲区的指针以及缓冲区的大小。可以使用INET_ADDRSTRLEN
和INET6_ADDRSTRLEN
分别表示IPv4和IPv6地址所需的最大缓冲区大小。
100.sockaddr数据结构
strcut sockaddr 很多网络编程函数诞生早于IPv4协议,那时候都使用的是sockaddr结构体,为了向前兼容,现在sockaddr退化成了(void *)的作用,传递一个地址给函数,至于这个函数是sockaddr_in还是sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型
101.请你来说一下socket编程中服务器端和客户端主要用到哪些函数?
请问你有没有基于做过socket的开发?具体网络层的操作该怎么做?
请你讲述一下Socket编程的send() recv() accept() socket()函数?
socket编程的流程?
基于TCP的socket
服务器端程序
(1)创建一个socket,用函数socket()
(2)绑定IP地址、端口等信息到socket上,用函数bind()
(3)设置允许的最大连接数,用函数listen()
(4)接收客户端上来的连接,用函数accept()
(5)收发数据,用函数send()和recv(),或者read()和write()
(6)关闭网络连接。
客户端程序:
(1)创建一个socket,用函数socket()
(2)设置要连接的对方的IP地址和端口等属性
(3)连接服务器,用函数connect()
(4)收发数据,用函数send()和recv(),或read()和write()
(5)关闭网络连接
基于UDP的socket
服务器端流程 (1)建立套接字文件描述符,使用函数socket(),生成套接字文件描述符。
(2)设置服务器地址和侦听端口,初始化要绑定的网络地址结构。
(3)绑定侦听端口,使用bind()函数,将套接字文件描述符和一个地址类型变量进行绑定。
(4)接收客户端的数据,使用recvfrom()函数接收客户端的网络数据。
(5)向客户端发送数据,使用sendto()函数向服务器主机发送数据。
(6)关闭套接字, 使用close()函数释放资源。UDP协议的客户端流程。
客户端流程
(1)建立套接字文件描述符,socket()。
(2)设置服务器地址和端口,struct sockaddr。
(3)向服务器发送数据,sendto()。
(4)接收服务器的数据,recvfrom()。
(5)关闭套接字,close()。
基于TCP的socket代码如下:
client.c的作用是从命令行参数中获得一个字符串发给服务器,然后接收服务器返回的字符串并打印。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXLINE 80
#define SERV_PORT 6666
int main(int argc, char *argv[])
{
struct sockaddr_in servaddr;
char buf[MAXLINE];
int sockfd, n;
char *str;
if (argc != 2) {
fputs("usage: ./client message\n", stderr);
exit(1);
}
str = argv[1];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
write(sockfd, str, strlen(str));
n = read(sockfd, buf, MAXLINE);
printf("Response from server:\n");
write(STDOUT_FILENO, buf, n);
close(sockfd);
return 0;
}
server.c的作用是从客户端读字符,然后将每个字符转换为大写并回送给客户端。
#include <s
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
查阅整理上千份嵌入式面经,将相关资料汇集于此,主要包括: 0.简历面试 1.语言篇 2.计算机基础 3.硬件篇 4.嵌入式Linux【本专栏】 (建议PC端查看)