【网络】网络编程套接字——UDP、TCP、UDP接口使用、TCP接口使用、UDP程序实例、TCP程序实例

文章目录

  • Linux网络
    • 1. UDP
      • 1.1 UDP接口使用
      • 1.1 UDP程序实例
    • 2. TCP
      • 2.1 TCP接口使用
      • 2.2 TCP程序实例

Linux网络

1. UDP

  在使用我们的UDP和TCP函数的时候,我们需要理解一些预备的知识:

源 IP 地址和目的 IP 地址:

  在网络通信中,IP 数据包头部的源 IP 地址和目的 IP 地址起着至关重要的作用。源 IP 地址指明了数据包的发送方所在的网络位置,就像寄信时的发信人地址;目的 IP 地址则指明了数据包的接收方所在的网络位置,如同收信人的地址。

  例如,当您在网上浏览网页时,您的设备(如电脑或手机)发送的请求数据包中就包含了您设备的源 IP 地址,而您所请求的网站服务器的 IP 地址则作为目的 IP 地址。

  但仅有 IP 地址并不足以完成完整的通信。以发送 QQ 消息为例,虽然 IP 地址能将消息送达对方的机器,但机器上可能运行着多个程序,还需要其他标识来确定这个数据应由哪个程序来解析处理,这就引入了端口号的概念。

  

端口号:

  端口号是传输层协议的重要组成部分,它是一个 2 字节 16 位的整数。端口号的作用在于标识一个进程,告诉操作系统应该将接收到的数据交给哪一个进程来处理。

  比如说,您的电脑上同时运行着浏览器和即时通讯软件,当网络数据到达时,端口号就像一个“指示牌”,告诉操作系统把数据准确地传递给对应的程序。

  就像一个电话号码,IP 地址能让数据找到正确的主机,而端口号则能让数据找到主机上正确的进程。

  IP 地址和端口号的组合能够唯一标识网络上某一台主机的某一个进程。

  

端口号和进程 ID(pid):

  在系统编程中,pid 用于唯一标识一个进程。而端口号在某种程度上也类似于 pid 对进程的标识作用。

  然而,它们之间也存在一些区别。pid 是操作系统内部用于管理进程的标识符,而端口号则主要用于网络通信中标识进程。

  例如,在一个服务器系统中,操作系统通过 pid 来管理进程的资源分配和调度,而当网络数据到达时,服务器通过端口号来确定将数据传递给哪个网络服务进程。

  

源端口号和目的端口号:

  在传输层协议(如 TCP 和 UDP)的数据段中,源端口号和目的端口号分别描述了“数据是谁发的,要发给谁”。

  比如,您通过浏览器访问一个网站,您的浏览器使用一个随机分配的源端口号(通常是大于 1024 的临时端口)向网站服务器的特定目的端口号(如 HTTP 协议通常使用 80 端口)发送请求,服务器接收到请求后,根据源端口号和目的端口号进行回应,从而完成一次完整的网络通信过程。

  
在这里插入图片描述

  

1.1 UDP接口使用

// 创建 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);

  

创建 UDP 套接字:

 // 创建 UDP 套接字int sockfd;if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("Socket creation failed");exit(EXIT_FAILURE);}

  “socket(AF_INET, SOCK_DGRAM, 0)”这个函数调用是用来创建一个套接字。

  “AF_INET”意思是使用 IPv4 地址格式

  “SOCK_DGRAM”表示创建的UDP数据报套接字,数据以独立的包发送,可能无序、丢失或重复。

  “0”让系统自动选择适合前面设置的默认传输协议,这里就是 UDP 协议。

  函数成功会返回一个套接字描述符,用于后续操作;失败则返回 -1 。

  

绑定端口号:

  struct sockaddr_in servaddr, cliaddr;memset(&servaddr, 0, sizeof(servaddr));memset(&cliaddr, 0, sizeof(cliaddr));// 填充服务器地址信息servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = INADDR_ANY;servaddr.sin_port = htons(PORT);// 绑定套接字到指定端口if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {perror("Bind failed");exit(EXIT_FAILURE);}

  我们首先定义了两个 struct sockaddr_in 类型的结构体 servaddr(服务器地址)和 cliaddr(客户端地址)。

  然后使用 memset 函数将这两个结构体的内存空间初始化为 0,以清除可能存在的垃圾数据。

  接下来为服务器地址结构体 servaddr 进行填充:

  servaddr.sin_family 设为 AF_INET,表示使用 IPv4 地址格式

  servaddr.sin_addr.s_addr 设为 INADDR_ANY,表示服务器可以接收来自任何本地 IPv4 地址的连接请求

  servaddr.sin_port 通过 htons 函数将指定的端口号(比如前面定义的 PORT)转换为网络字节序并进行设置。

  最后,使用 bind 函数将创建的套接字 sockfd 与填充好的服务器地址 servaddr 进行绑定。如果绑定失败,会打印错误信息并退出程序。

  

网络字节序:

  网络字节序是网络数据流的规定格式,采用大端字节序(低地址高字节)。

  TCP/IP 协议要求网络数据按这种格式传输。发送主机按内存地址从低到高发送数据,接收主机也按内存地址从低到高保存数据。

  不管主机是大端还是小端字节序,都要按网络字节序发送/接收数据。小端主机需转换数据,大端主机可直接发送。

  为让网络程序在不同主机都能正常运行,可调用库函数进行网络字节序和主机字节序转换,htons、htonl、ntohs、ntohl 。

  

sockaddr结构:

  Socket API 是适用于多种底层网络协议的抽象编程接口,如 IPv4、IPv6 及 UNIX Domain Socket 。IPv4 地址用 sockaddr_in 结构体表示,其包含地址类型、端口号和 IP 地址。

  IPv4、IPv6 地址类型分别定义为常数 AF_INET 、 AF_INET6 。Socket API 都能用 struct sockaddr * 类型表示,使用时需强制转化为 sockaddr_in ,好处是使程序具有通用性,能接收各种类型的 sockaddr 结构体指针作为参数。

  

  sockaddr_in 结构:

  虽然socket api的接口是sockaddr,但是我们真正在基于IPv4编程时,使用的数据结构是sockaddr_in,这个结构里主要有三部分信息:地址类型,端口号,IP地址。

  

  in_addr结构:

  in_addr用来表示一个IPv4的IP地址,其实就是一个32位的整数。

  

1.1 UDP程序实例

UdpServer.hpp

#pragma once#include <iostream>
#include <string>
#include <strings.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <unordered_map>
#include "Log.hpp"// using func_t = std::function<std::string(const std::string&)>;
typedef std::function<std::string(const std::string &, const std::string &, uint16_t)> func_t;Log lg;enum{SOCKET_ERR=1,BIND_ERR
};uint16_t defaultport = 8080;
std::string defaultip = "0.0.0.0";
const int size = 1024;class UdpServer{
public:UdpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip):sockfd_(0), port_(port), ip_(ip),isrunning_(false){}void Init(){// 1. 创建udp socket// 2. Udp 的socket是全双工的,允许被同时读写的sockfd_ = socket(AF_INET, SOCK_DGRAM, 0); // PF_INETif(sockfd_ < 0){lg(Fatal, "socket create error, sockfd: %d", sockfd_);exit(SOCKET_ERR);}lg(Info, "socket create success, sockfd: %d", sockfd_);// 2. bind socketstruct sockaddr_in local;bzero(&local, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port_); //需要保证我的端口号是网络字节序列,因为该端口号是要给对方发送的local.sin_addr.s_addr = inet_addr(ip_.c_str()); //1. string -> uint32_t 2. uint32_t必须是网络序列的 // ??// local.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(sockfd_, (const struct sockaddr *)&local, sizeof(local)) < 0){lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));exit(BIND_ERR);}lg(Info, "bind success, errno: %d, err string: %s", errno, strerror(errno));}void CheckUser(const struct sockaddr_in &client, const std::string clientip, uint16_t clientport){auto iter = online_user_.find(clientip);if(iter == online_user_.end()){online_user_.insert({clientip, client});std::cout << "[" << clientip << ":" << clientport << "] add to online user." << std::endl;}}void Broadcast(const std::string &info, const std::string clientip, uint16_t clientport){for(const auto &user : online_user_){std::string message = "[";message += clientip;message += ":";message += std::to_string(clientport);message += "]# ";message += info;socklen_t len = sizeof(user.second);sendto(sockfd_, message.c_str(), message.size(), 0, (struct sockaddr*)(&user.second), len);}}void Run() // 对代码进行分层{isrunning_ = true;char inbuffer[size];while(isrunning_){struct sockaddr_in client;socklen_t len = sizeof(client);ssize_t n = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&client, &len);if(n < 0){lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));continue;}uint16_t clientport = ntohs(client.sin_port);std::string clientip = inet_ntoa(client.sin_addr);CheckUser(client, clientip, clientport);std::string info = inbuffer;Broadcast(info,clientip, clientport);}}~UdpServer(){if(sockfd_>0) close(sockfd_);}
private:int sockfd_;     // 网路文件描述符std::string ip_; // 任意地址bind 0uint16_t port_;  // 表明服务器进程的端口号bool isrunning_;std::unordered_map<std::string, struct sockaddr_in> online_user_;
};

  

UdpClient.cc

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "Terminal.hpp"using namespace std;void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " serverip serverport\n"<< std::endl;
}struct ThreadData
{struct sockaddr_in server;int sockfd;std::string serverip;
};void *recv_message(void *args)
{// OpenTerminal();ThreadData *td = static_cast<ThreadData *>(args);char buffer[1024];while (true){memset(buffer, 0, sizeof(buffer));struct sockaddr_in temp;socklen_t len = sizeof(temp);ssize_t s = recvfrom(td->sockfd, buffer, 1023, 0, (struct sockaddr *)&temp, &len);if (s > 0){buffer[s] = 0;cerr << buffer << endl;}}
}void *send_message(void *args)
{ThreadData *td = static_cast<ThreadData *>(args);string message;socklen_t len = sizeof(td->server);std::string welcome = td->serverip;welcome += " comming...";sendto(td->sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&(td->server), len);while (true){cout << "Please Enter@ ";getline(cin, message);// std::cout << message << std::endl;// 1. 数据 2. 给谁发sendto(td->sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&(td->server), len);}
}// 多线程
// ./udpclient serverip serverport
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(0);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);struct ThreadData td;bzero(&td.server, sizeof(td.server));td.server.sin_family = AF_INET;td.server.sin_port = htons(serverport); //?td.server.sin_addr.s_addr = inet_addr(serverip.c_str());td.sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (td.sockfd < 0){cout << "socker error" << endl;return 1;}td.serverip = serverip;pthread_t recvr, sender;pthread_create(&recvr, nullptr, recv_message, &td);pthread_create(&sender, nullptr, send_message, &td);pthread_join(recvr, nullptr);pthread_join(sender, nullptr);close(td.sockfd);return 0;
}

  

2. TCP

TCPUDP
可靠传输不可靠传输
有连接无连接
字节流数据报

  

2.1 TCP接口使用

// 创建 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);

  

创建TCP套接字:

 // 创建套接字if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("Socket creation failed");return -1;}

  socket(AF_INET, SOCK_STREAM, 0) 这个函数来做创建套接字。

  AF_INET 是 IPv4 地址族

  SOCK_STREAM 表示要创建 TCP 套接字

  最后的 0 让系统选合适协议,这里就是 TCP 协议。

  要是创建失败(server_fd 为 0 ),就输出错误信息,程序返回 -1 结束。

  

绑定套接字:

 struct sockaddr_in address;int addrlen = sizeof(address);address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);// 绑定if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("Bind failed");return -1;}

  我们先定义了一个 sockaddr_in 结构体 address 并获取其大小。然后为 address 结构体的成员赋值:

  sin_family 设为 AF_INET,表示使用 IPv4 地址格式。

  sin_addr.s_addr 设为 INADDR_ANY,表示服务器可以接收来自任何本地 IPv4 地址的连接请求。

  sin_port 通过 htons 函数将指定的端口号(比如前面定义的 PORT)转换为网络字节序并进行设置。

  接下来使用 bind 函数将创建的套接字 server_fd 与填充好的 address 结构体进行绑定。如果绑定失败,会输出错误信息并返回 -1 结束程序。

  

监听套接字:

 // 监听if (listen(server_fd, 3) < 0) {perror("Listen failed");return -1;}

  我们使用 listen 函数让服务器套接字 server_fd 进入监听状态。

  参数 3 表示等待连接队列的最大长度。

  如果 listen 函数执行失败(返回值小于 0 ),就会输出错误信息 “Listen failed” ,然后程序返回 -1 结束运行。

  

接收连接:

  // 接受连接if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) {perror("Accept failed");return -1;}

  我们通过 accept 函数来接受客户端的连接请求。

  如果成功,会返回一个新的套接字描述符 new_socket ,用于与客户端进行后续的通信。
同时,会将客户端的地址信息填充到 address 结构体中,addrlen 则用于记录客户端地址的长度。

  如果 accept 函数执行失败(返回值小于 0 ),就会输出错误信息 “Accept failed” ,然后程序返回 -1 结束。

  

接收数据:

 // 接收数据int received = recv(new_socket, buffer, sizeof(buffer), 0);if (received < 0) {perror("Receive failed");return -1;}

  我们使用 recv 函数从与客户端连接的新套接字 new_socket 中接收数据,并将接收到的数据存储到 buffer 数组中

  received 变量用于记录实际接收到的数据字节数。

  如果接收数据失败(received 的值小于 0 ),就会输出错误信息 “Receive failed” ,然后程序返回 -1 结束。

  

发送数据:

  // 发送数据char *response = "Hello client!";send(new_socket, response, strlen(response), 0);

  我们使用 send 函数通过新套接字 new_socket 向客户端发送这个数据

  strlen(response) 用于获取响应字符串的长度。

  最后一个参数 0 表示默认的发送选项。

  

关闭连接:

 close(new_socket);close(server_fd);

  close(new_socket) 关闭与客户端通信的套接字 new_socket 。

  close(server_fd) 关闭服务器端创建的监听套接字 server_fd 。

  关闭套接字可以释放相关的资源,并结束与客户端的连接和服务器的监听状态。

  

2.2 TCP程序实例

TcpServer.hpp

#pragma once#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <signal.h>
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Daemon.hpp"const int defaultfd = -1;
const std::string defaultip = "0.0.0.0";
const int backlog = 10; // 但是一般不要设置的太大
extern Log lg;enum
{UsageError = 1,SocketError,BindError,ListenError,
};class TcpServer;class ThreadData
{
public:ThreadData(int fd, const std::string &ip, const uint16_t &p, TcpServer *t): sockfd(fd), clientip(ip), clientport(p), tsvr(t){}
public:int sockfd;std::string clientip;uint16_t clientport;TcpServer *tsvr;
};class TcpServer
{
public:TcpServer(const uint16_t &port, const std::string &ip = defaultip) : listensock_(defaultfd), port_(port), ip_(ip){}void InitServer(){listensock_ = socket(AF_INET, SOCK_STREAM, 0);if (listensock_ < 0){lg(Fatal, "create socket, errno: %d, errstring: %s", errno, strerror(errno));exit(SocketError);}lg(Info, "create socket success, listensock_: %d", listensock_);int opt = 1;setsockopt(listensock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt)); // 防止偶发性的服务器无法进行立即重启(tcp协议的时候再说)struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port_);inet_aton(ip_.c_str(), &(local.sin_addr));// local.sin_addr.s_addr = INADDR_ANY;if (bind(listensock_, (struct sockaddr *)&local, sizeof(local)) < 0){lg(Fatal, "bind error, errno: %d, errstring: %s", errno, strerror(errno));exit(BindError);}lg(Info, "bind socket success, listensock_: %d", listensock_);// Tcp是面向连接的,服务器一般是比较“被动的”,服务器一直处于一种,一直在等待连接到来的状态if (listen(listensock_, backlog) < 0){lg(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));exit(ListenError);}lg(Info, "listen socket success, listensock_: %d", listensock_);}// static void *Routine(void *args)// {//     pthread_detach(pthread_self());//     ThreadData *td = static_cast<ThreadData *>(args);//     td->tsvr->Service(td->sockfd, td->clientip, td->clientport);//???//     delete td;//     return nullptr;// }void Start(){Daemon();ThreadPool<Task>::GetInstance()->Start();// for fork();// signal(SIGCHLD, SIG_IGN);lg(Info, "tcpServer is running....");for (;;){// 1. 获取新连接struct sockaddr_in client;socklen_t len = sizeof(client);int sockfd = accept(listensock_, (struct sockaddr *)&client, &len);if (sockfd < 0){lg(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno)); //?continue;}uint16_t clientport = ntohs(client.sin_port);char clientip[32];inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));// 2. 根据新连接来进行通信lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, clientip, clientport);// std::cout << "hello world" << std::endl;// version 1 -- 单进程版// Service(sockfd, clientip, clientport);// close(sockfd);// version 2 -- 多进程版// pid_t id = fork();// if(id == 0)// {//     // child//     close(listensock_);//     if(fork() > 0) exit(0);//     Service(sockfd, clientip, clientport); //孙子进程, system 领养//     close(sockfd);//     exit(0);// }// close(sockfd);// // father// pid_t rid = waitpid(id, nullptr, 0);// (void)rid;// version 3 -- 多线程版本// ThreadData *td = new ThreadData(sockfd, clientip, clientport, this);// pthread_t tid;// pthread_create(&tid, nullptr, Routine, td);// version 4 --- 线程池版本Task t(sockfd, clientip, clientport);ThreadPool<Task>::GetInstance()->Push(t);}}// void Service(int sockfd, const std::string &clientip, const uint16_t &clientport)// {//     // 测试代码//     char buffer[4096];//     while (true)//     {//         ssize_t n = read(sockfd, buffer, sizeof(buffer));//         if (n > 0)//         {//             buffer[n] = 0;//             std::cout << "client say# " << buffer << std::endl;//             std::string echo_string = "tcpserver echo# ";//             echo_string += buffer;//             write(sockfd, echo_string.c_str(), echo_string.size());//         }//         else if (n == 0)//         {//             lg(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);//             break;//         }//         else//         {//             lg(Warning, "read error, sockfd: %d, client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);//             break;//         }//     }// }~TcpServer() {}private:int listensock_;uint16_t port_;std::string ip_;
};

  

TcpClient.cc

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>void Usage(const std::string &proc)
{std::cout << "\n\rUsage: " << proc << " serverip serverport\n"<< std::endl;
}// ./tcpclient serverip serverport
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(1);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport);inet_pton(AF_INET, serverip.c_str(), &(server.sin_addr));while (true){int cnt = 5;int isreconnect = false;int sockfd = 0;sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){std::cerr << "socket error" << std::endl;return 1;}do{// tcp客户端要不要bind?1 要不要显示的bind?0 系统进行bind,随机端口// 客户端发起connect的时候,进行自动随机bindint n = connect(sockfd, (struct sockaddr *)&server, sizeof(server));if (n < 0){isreconnect = true;cnt--;std::cerr << "connect error..., reconnect: " << cnt << std::endl;sleep(2);}else{break;}} while (cnt && isreconnect);if (cnt == 0){std::cerr << "user offline..." << std::endl;break;}// while (true)// {std::string message;std::cout << "Please Enter# ";std::getline(std::cin, message);int n = write(sockfd, message.c_str(), message.size());if (n < 0){std::cerr << "write error..." << std::endl;// break;}char inbuffer[4096];n = read(sockfd, inbuffer, sizeof(inbuffer));if (n > 0){inbuffer[n] = 0;std::cout << inbuffer << std::endl;}else{// break;}// }close(sockfd);}return 0;
}

            

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/875686.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电脑软件:推荐一款非常好用的图片编辑软件——Photo Pos Pro

目录 一、软件简介 二、功能介绍 三、使用说明 四、软件特点 一、软件简介 Photo Pos Pro 4是一款非常实用的图像编辑软件&#xff0c;专为需要修图的用户量身打造而成。软件拥有简洁的用户界面&#xff0c;操作起来也比较简单&#xff0c;能够帮助用户轻松处理图片。软件具…

蚂蚁集团Android一面凉经(2024)

蚂蚁集团Android一面凉经(2024) 笔者作为一名双非二本毕业7年老Android, 最近面试了不少公司, 目前已告一段落, 整理一下各家的面试问题, 打算陆续发布出来, 供有缘人参考。今天给大家带来的是《蚂蚁集团Android一面凉经(2024)》。 面试职位: 蚂蚁集团-Android/iOS开发工程师-支…

MySQL练手 --- 1174. 即时食物配送 II

题目链接&#xff1a;1174. 即时食物配送 II 思路&#xff1a; 题目要求&#xff1a;即时订单在所有用户的首次订单中的比例。保留两位小数 其实也就是 即时订单 / 首次订单 所以&#xff0c;先求出首次订单&#xff0c;在首次订单的基础上寻找即时订单即可 解题过程&#x…

介绍下PolarDB

业务中用的是阿里云自研的PolarDB&#xff0c;分析下PolarDB的架构。 认识PolarDB 介绍 PolarDB是阿里云自研的&#xff0c;兼容MySQL、PostageSQL以及支持MPP的PolarDB-X的高可用、高扩展性的数据库。 架构 部署 云起实验室 - 阿里云开发者社区 - 阿里云 (aliyun.com) 数…

IDEA新建module后变为普通文件夹

问题描述&#xff1a; 在父项目中创建module并构建子父关系&#xff0c;但在创建module并配置后出现未生效问题 在父项目中的pom.xml文件中添加 <modules><module>***</module></modules>在新建Module中添加 <parent><groupId>com.***&l…

嵌入式中什么是三次握手

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「嵌入式的资料从专业入门到高级教程」&#xff0c;点个关注在评论区回复“666”之后私信回复“666”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 在网络数据传输中&#xf…

Qt自定义带前后缀图标的PushButton

写在前面 Qt提供QPushButton不满足带前后缀图标的需求&#xff0c;因此考虑自定义实现带前后缀图标的PushButton&#xff0c;方便后续快速使用。 效果如下&#xff1a; 同时可设置前后缀图标和文本之间间隙&#xff1a; 代码实现 通过前文介绍的Qt样式表底层实现 可以得…

【人工智能】AI绘画:科技与艺术交汇的新时代

文章目录 &#x1f34a;AI绘画:开启艺术创作新纪元AI绘画技术发展&#xff1a;算法与艺术的完美交融AI绘画的工作原理与创意生成AI绘画的应用 AI绘画工具介绍 &#x1f34a;AI绘画:开启艺术创作新纪元 人工智能正以前所未有的力量重塑我们的世界&#xff0c;而AI绘画作为这股科…

0725,进程间传递文件描述符,socketpair + sendmsg/recvmsg

我要碎掉了我要碎掉了我要碎掉了 上课喵&#xff1a; pipe匿名管道的问题 #include <func.h>int main() {int fds[2];pipe(fds);pid_t pidfork();if(pid>0){ //fatherclose(fds[0]);//close readint fdopen("file2.txt",O_RDONLY);printf("father: …

如何安全的申请SSL证书

随着数字化时代的快速发展&#xff0c;互联网政务应用已成为政府服务民众、提升治理效能的重要途径。在这个网络日益复杂的时代&#xff0c;政务网站的安全问题显得尤为重要。2024年&#xff0c;国家出台并从2024年7月1日开始实施执行《互联网政务应用安全管理规定》&#xff0…

常见的CSS属性(一)——字体、文本、边框、内边距、外边距、背景、行高、圆角、透明度、颜色值

一、字体 二、文本 三、边框 四、外边距 五、内边距 六、背景 七、行高 八、圆角 九、透明度 九、颜色值 元素的继承性是指给父元素设置了某些属性&#xff0c;子元素或后代元素也会有作用。 一、字体 “font-*”是字体相关的属性&#xff0c;具有继承性。代码如下&a…

Github 2024-07-26 Java开源项目日报 Top10

根据Github Trendings的统计,今日(2024-07-26统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目9HTML项目1TypeScript项目1非开发语言项目1JavaGuide - Java 程序员学习和面试指南 创建周期:2118 天开发语言:Java协议类型:Apache…

Matlab编程资源库(7)图形修饰处理

一、视点处理 MATLAB 提供了 设置视点 的函数 view &#xff0c;其调用格式 为&#xff1a; view(az,el) 其中 az 为 方位角 &#xff0c; el 为 仰角 &#xff0c;它们均以度为单位。 系统缺省的视点定义为方位角-37.5 , 仰角30 。 二、色彩处理 1 &#xff0e;颜色的向量…

【前端学习】CSS三大特性

CSS三大特性 CSS的三大特性是为了化简代码、定位问题并且解决问题 继承性 继承性特点&#xff1a; 子级默认继承父级的文字控制属性。注意&#xff1a;如果标签自己有样式则生效自己的样式&#xff0c;不继承。 <!DOCTYPE html> <html lang"en"><…

windows USB 设备驱动开发- WinUSB 简介

WinUSB 是 Windows 随附的 USB 设备的通用驱动程序。WinUSB 包括&#xff1a; 内核模式驱动程序 (Winusb.sys)&#xff1b;公开 winusb.h 中所述的 WinUSB 函数的用户模式动态链接库 (Winusb.dll)。 借助这些函数&#xff0c;你可以使用用户模式软件管理 USB 设备&#xff1b;…

12 位运算符

位运算符只能用于整数&#xff0c;其内部执行过程为&#xff1a;首先将整数转换为二进制数&#xff0c;然后右对齐&#xff0c;必要时左侧补0&#xff0c;按位进行运算&#xff0c;最后再把计算结果转换为十进制数字返回。 ① 左移&#xff1a;高位丢弃&#xff0c;低位补0&…

Exponential Moving Average (EMA) in Stable Diffusion

1.Moving Average in Stable Diffusion (SMA&EMA) 1.Moving average 2.移动平均值 3.How We Trained Stable Diffusion for Less than $50k (Part 3) Moving Average 在统计学中&#xff0c;移动平均是通过创建整个数据集中不同选择的一系列平均值来分析数据点的计算。 …

数据结构与算法-插入排序

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、插入排…

unity ui toolkit的使用

UIToolkitExamples (github)样例 GitHub - ikewada/UIToolkitExamples: チュートリアル動画「使ってみようUI Toolkit」のためのサンプルプロジェクトです官网 Unity - Manual: UI Toolkit视频教程 使用 UI Toolkit - 上集_哔哩哔哩_bilibili 使用 UI Toolkit - 下集_哔哩哔哩_…

Java | Leetcode Java题解之第283题移动零

题目&#xff1a; 题解&#xff1a; class Solution {public void moveZeroes(int[] nums) {int n nums.length, left 0, right 0;while (right < n) {if (nums[right] ! 0) {swap(nums, left, right);left;}right;}}public void swap(int[] nums, int left, int right)…