Linux下SOCKET编程

news2025/1/12 23:01:45

一、SOCKET编程

1、socket()函数

int  socket(int protofamily, int type, int protocol);//返回sockfd

返回值sockfd是描述符。
socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。

  • 文件描述符:在linux系统中打开文件就会获得文件描述符,它是个很小的正整数。每个进程在PCB(Process Control Block)中保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针。
  • 文件指针:C语言中使用文件指针做为I/O的句柄。文件指针指向进程用户区中的一个被称为FILE结构的数据结构。FILE结构包括一个缓冲区和一个文件描述符。而文件描述符是文件描述符表的一个索引,因此从某种意义上说文件指针就是句柄的句柄(在Windows系统上,文件描述符被称作文件句柄)。

正如可以给fopen的传入不同参数值,以打开不同的文件。创建socket的时候,也可以指定不同的参数创建不同的socket描述符,socket函数的三个参数分别为:

  • protofamily:即协议域,又称为协议族(family)。常用的协议族有,AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。

  • type:指定socket类型。常用的socket类型有,SOCK_STREAM(用于TCP)、SOCK_DGRAM(用于UDP)、SOCK_RAW(用于提供原始网络访问)、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。

  • protocol:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口。

2、bind()函数
正如上面所说bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。

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

函数的三个参数分别为:

  • sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。
  • addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同,如ipv4对应的是:
		struct sockaddr_in {
		    sa_family_t    sin_family; /* address family: AF_INET */
		    in_port_t      sin_port;   /* port in network byte order */
		    struct in_addr sin_addr;   /* internet address */
		};
		 
		/* Internet address. */
		struct in_addr {
		    uint32_t       s_addr;     /* address in network byte order */
		};

ipv6对应的是:

		struct sockaddr_in6 { 
		    sa_family_t     sin6_family;   /* AF_INET6 */ 
		    in_port_t       sin6_port;     /* port number */ 
		    uint32_t        sin6_flowinfo; /* IPv6 flow information */ 
		    struct in6_addr sin6_addr;     /* IPv6 address */ 
		    uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
		};
		 
		struct in6_addr { 
		    unsigned char   s6_addr[16];   /* IPv6 address */ 
		};
  • addrlen:对应的是地址的长度。
    通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。
    3、listen()、connect()函数
    如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。
int listen(int sockfd, int backlog);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。

4、accept()函数
TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就向TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //返回连接connect_fd

参数sockfd
参数sockfd就是上面解释中的监听套接字,这个套接字用来监听一个端口,当有一个客户与服务器连接时,它使用这个一个端口号,而此时这个端口号正与这个套接字关联。当然客户不知道套接字这些细节,它只知道一个地址和一个端口号。
参数addr
这是一个结果参数,它用来接受一个返回值,这返回值指定客户端的地址,当然这个地址是通过某个地址结构来描述的,用户应该知道这一个什么样的地址结构。如果对客户的地址不感兴趣,那么可以把这个值设置为NULL。
参数len
如同大家所认为的,它也是结果的参数,用来接受上述addr的结构的大小的,它指明addr结构所占有的字节个数。同样的,它也可以被设置为NULL。
如果accept成功返回,则服务器与客户已经正确建立连接了,此时服务器通过accept返回的套接字来完成与客户的通信。
注意:
== accept默认会阻塞进程,直到有一个客户连接建立后返回,它返回的是一个新可用的套接字,这个套接字是连接套接字。==
此时我们需要区分两种套接字:
监听套接字: 监听套接字正如accept的参数sockfd,它是监听套接字,在调用listen函数之后,是服务器开始调用socket()函数生成的,称为监听socket描述字(监听套接字)
连接套接字:一个套接字会从主动连接的套接字变身为一个监听套接字;而accept函数返回的是已连接socket描述字(一个连接套接字),它代表着一个网络已经存在的点点连接。
一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。
自然要问的是:为什么要有两种套接字?原因很简单,如果使用一个描述字的话,那么它的功能太多,使得使用很不直观,同时在内核确实产生了一个这样的新的描述字。
连接套接字socketfd_new 并没有占用新的端口与客户端通信,依然使用的是与监听套接字socketfd一样的端口号

linux下tcp服务器和客户端连接和传输消息的过程
在这里插入图片描述服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

5、read()、write()等函数
至此服务器与客户已经建立好连接了。可以调用网络I/O进行读写操作了,即实现了网咯中不同进程之间的通信!网络I/O操作有下面几组:

read()/write()
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendto()

推荐使用recvmsg()/sendmsg()函数,这两个函数是最通用的I/O函数,实际上可以把上面的其它函数都替换成这两个函数。它们的声明如下:

	    #include <unistd.h>
	    
       ssize_t read(int fd, void *buf, size_t count);
       ssize_t write(int fd, const void *buf, size_t count);
 
       #include <sys/types.h>
       #include <sys/socket.h>
 
       ssize_t send(int sockfd, const void *buf, size_t len, int flags);
       ssize_t recv(int sockfd, void *buf, size_t len, int flags);
 
       ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);
       ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);
 
       ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
       ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0表示已经读到文件的结束了,小于0表示出现了错误。如果错误为EINTR说明读是由中断引起的,如果是ECONNREST表示网络连接出了问题。

write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数。失败时返回-1,并设置errno变量。 在网络程序中,当我们向套接字文件描述符写时有俩种可能。1)write的返回值大于0,表示写了部分或者是全部的数据。2)返回的值小于0,此时出现了错误。我们要根据错误类型来处理。如果错误为EINTR表示在写的时候出现了中断错误。如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接)。

6、close()函数
在服务器与客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的socket描述字,好比操作完打开的文件要调用fclose关闭打开的文件。

#include <unistd.h>
int close(int fd);

close一个TCP socket的缺省行为时把该socket标记为以关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为read或write的第一个参数。
注意:close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

TCP/IP连接

首先是服务器程序,监听的是8080端口

/* File Name: server.c */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define DEFAULT_PORT 8080
#define MAXLINE 4096
int main(int argc, char** argv)
{
    int    socket_fd, connect_fd;
    struct sockaddr_in     servaddr;
    char    buff[4096];
    int     n;
    //1、创建socket,获得一个socket_fd 描述符,AF_INET是IPV4,SOCK_STREAM代表使用TCP
    if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
    printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }
    //2、初始化参数,设置协议、绑定监听的端口号、IP
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;   //IPV4
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。
    servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为DEFAULT_PORT
 
    //3、将本地地址绑定到所创建的套接字上
    if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
    {
    		printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
    		exit(0);
    }
    //4、开始监听是否有客户端连接
    if( listen(socket_fd, 10) == -1){
    printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }
    printf("======waiting for client's request======\n");
    while(1)
    {
			//5、阻塞直到有客户端连接,不然多浪费CPU资源
        if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1)
        {
        	 printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
        	 continue;
    		}
			//6、接受客户端传过来的数据
    		n = recv(connect_fd, buff, MAXLINE, 0);
    		
			//7、向客户端发送回应数据
    		if(!fork()) /*子进程*/
    		{
        	 if(send(connect_fd, "Hello,you are connected!\n", 26,0) == -1)
        	 perror("send error");
       	 close(connect_fd);
        	 exit(0);
    		}
    		buff[n] = '\0';
    		printf("recv msg from client: %s\n", buff);
   		close(connect_fd);
    }
    close(socket_fd);
}

客户端

/* File Name: client.c */ 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
 
#define MAXLINE 4096

int main(int argc, char** argv)
{
    int    sockfd, n,rec_len;
    char    recvline[4096], sendline[4096];
    char    buf[MAXLINE];
    struct sockaddr_in    servaddr;
    
    if( argc != 2){
    printf("usage: ./client <ipaddress>\n");
    exit(0);
    }
		
	  // 创建socket,SOCK_STREAM代表使用TCP
    if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
    printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
    exit(0);
    }
 	
 	  //初始化将要连接的服务器的端口,协议,服务器的IP(argv[1])
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(8080);
    if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
    {
    		printf("inet_pton error for %s\n",argv[1]);
    		exit(0);
    }
 	  //连接服务器
    if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    {
    		printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
    		exit(0);
    }
 
    printf("send msg to server: \n");
    fgets(sendline, 4096, stdin);
    if( send(sockfd, sendline, strlen(sendline), 0) < 0)
    {
    		printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
    		exit(0);
    }
    if((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) 
    {
       perror("recv error");
       exit(1);
    }
    buf[rec_len]  = '\0';
    printf("Received : %s ",buf);
    close(sockfd);
    exit(0);
}

inet_pton 是Linux下IP地址转换函数,可以在将IP地址在“点分十进制”和“整数”之间转换 ,是inet_addr的扩展。

int inet_pton(int af, const char *src, void *dst);//转换字符串到网络地址:

第一个参数af是地址族,转换后存在dst中
af = AF_INET: src为指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函数将该地址转换为in_addr的结构体,并复制在dst中
af =AF_INET6: src为指向IPV6的地址,函数将该地址转换为in6_addr的结构体,并复制在
dst中
如果函数出错将返回一个负值,并将errno设置为EAFNOSUPPORT,如果参数af指定的地址族和src格式不对,函数将返回0。

测试:
编译server.c
gcc -o server server.c
启动进程:
./server

编译 client.c
gcc -o client client.c
客户端去连接server:
./client 127.0.0.1

在这里插入图片描述

TCP多线程并发服务器请看这片文章:

https://blog.csdn.net/qq_40170041/article/details/125164359?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22125164359%22%2C%22source%22%3A%22qq_40170041%22%7D

UDP

linux下UDP服务器和客户端连接和传输消息的过程
在这里插入图片描述客户端要发起一次请求,仅仅需要两个步骤(socket和sendto),而服务器端也仅仅需要三个步骤即可接收到来自客户端的消息(socket、bind、recvfrom)。
前面讲过了socket函数
bind

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);

第一个参数sockfd:正在监听端口的套接口文件描述符,通过socket获得
第二个参数my_addr:需要绑定的IP和端口
第三个参数addrlen:my_addr的结构体的大小
返回值:成功:0
失败:-1

sendto

#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
              const struct sockaddr *dest_addr, socklen_t addrlen);

第一个参数sockfd:正在监听端口的套接口文件描述符,通过socket获得
第二个参数buf:发送缓冲区,往往是使用者定义的数组,该数组装有要发送的数据
第三个参数len:发送缓冲区的大小,单位是字节
第四个参数flags:填0即可
第五个参数dest_addr:指向接收数据的主机地址信息的结构体,也就是该参数指定数据要发送到哪个主机哪个进程
第六个参数addrlen:表示第五个参数所指向内容的长度
返回值:成功:返回发送成功的数据长度
失败: -1

recvfrom

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

第一个参数sockfd:正在监听端口的套接口文件描述符,通过socket获得
第二个参数buf:接收缓冲区,往往是使用者定义的数组,该数组装有接收到的数据
第三个参数len:接收缓冲区的大小,单位是字节
第四个参数flags:填0即可
第五个参数src_addr:指向发送数据的主机地址信息的结构体,也就是我们可以从该参数获取到数据是谁发出的
第六个参数addrlen:表示第五个参数所指向内容的长度
返回值:成功:返回接收成功的数据长度
失败: -1

UDP server:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

#define SERVER_PORT 8081
#define BUFF_LEN 1024

void handle_udp_msg(int fd)
{
     char buf[BUFF_LEN];  //接收缓冲区,1024字节
     socklen_t len;
     int count;
     struct sockaddr_in clent_addr;  //clent_addr用于记录发送方的地址信息
     while(1)
     {
         memset(buf, 0, BUFF_LEN);
         len = sizeof(clent_addr);
         count = recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&clent_addr, &len);  //recvfrom是拥塞函数,没有数据就一直拥塞
         if(count == -1)
         {
             printf("recieve data fail!\n");
             return;
         }
         printf("client:%s\n",buf);  //打印client发过来的信息
         memset(buf, 0, BUFF_LEN);
         sprintf(buf, "I have recieved %d bytes data!\n", count);  //回复client
         printf("server:%s\n",buf);  //打印自己发送的信息给
         sendto(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&clent_addr, len);  //发送信息给client,注意使用了clent_addr结构体指针
 
     }
 }
 /*
     server:
             socket-->bind-->recvfrom-->sendto-->close
 */
 int main(int argc, char* argv[])
 {
     int server_fd, ret;
     struct sockaddr_in ser_addr; 
     //1、创建socket,SOCK_DGRAM代表UDP协议
     server_fd = socket(AF_INET, SOCK_DGRAM, 0); //AF_INET:IPV4;SOCK_DGRAM:UDP
     if(server_fd < 0)
     {
         printf("create socket fail!\n");
         return -1;
     }
 		
 		//初始化UDP服务器需要监听的IP地址和端口号
     memset(&ser_addr, 0, sizeof(ser_addr));
     ser_addr.sin_family = AF_INET;
     ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址
     ser_addr.sin_port = htons(SERVER_PORT);  //端口号,需要网络序转换
 		//绑定需要监听的IP和端口号
     ret = bind(server_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
     if(ret < 0)
     {
         printf("socket bind fail!\n");
         return -1;
     }
 
     handle_udp_msg(server_fd);   //处理接收到的数据
 
     close(server_fd);
     return 0;
}

UDP client

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

#define SERVER_PORT 8081
#define BUFF_LEN 512
#define SERVER_IP "127.0.0.1"
  
void udp_msg_sender(int fd, struct sockaddr* dst)
{
     socklen_t len;
     struct sockaddr_in src;
     while(1)
     {
         char buf[BUFF_LEN] = "TEST UDP MSG!\n";
         len = sizeof(*dst);
         printf("client:%s\n",buf);  //打印自己发送的信息
         sendto(fd, buf, BUFF_LEN, 0, dst, len);
         memset(buf, 0, BUFF_LEN);
         recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&src, &len);  //接收来自server的信息
         printf("server:%s\n",buf);
         sleep(1);  //一秒发送一次消息
     }
}
/*
     client:
             socket-->sendto-->revcfrom-->close
*/
int main(int argc, char* argv[])
{
     int client_fd;
     struct sockaddr_in ser_addr;
 
     client_fd = socket(AF_INET, SOCK_DGRAM, 0);
     if(client_fd < 0)
     {
         printf("create socket fail!\n");
         return -1;
     }
 
     memset(&ser_addr, 0, sizeof(ser_addr));
     ser_addr.sin_family = AF_INET;
     ser_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
     //ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //注意网络序转换
     ser_addr.sin_port = htons(SERVER_PORT);  //注意网络序转换
     
     udp_msg_sender(client_fd, (struct sockaddr*)&ser_addr);
 
     close(client_fd);
     return 0;
}

gcc udp_server.c -o udpServer
gcc udp_server.c -o udpServer

在这里插入图片描述

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

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

相关文章

2. C++使用Thread线程参数传递问题

1. 说明 在子线程函数中进行参数传递&#xff0c;实际上是Thread类的构造函数对传递的参数进行了拷贝&#xff0c;拷贝到线程独立的内存中&#xff0c;及时参数是引用的形式&#xff0c;也可以在新线程中进行访问&#xff0c;如果参数传递时的类型不一致&#xff0c;在线程的上…

Servlet(二)

目录 1.Cookie 和 Session 1.1HttpServletRequest 类中的相关方法 1.HttpSession getSession() 2.Cookie[] getCookies() 1.2HttpServletResponse 类中的相关方法 1.void addCookie(Cookie cookie) 1.3HttpSession 类中的相关方法 1.4Cookie 类中的相关方法 1.5网页登录…

详解Spring Security

目录 1.概述 2.登录 2.1.默认用户 2.2.自定义用户 2.3.加密 2.4.绕过加密 2.5.怎么传递用户信息 2.6.记住我 3.登出 4.使用数据库 4.1.jdbcAuthentication 4.2.userDetailsService 5.自定义处理器 6.更多细粒度的控制 7.原理简述 1.概述 Spring Security是一个…

使用 Kubernetes 运行 non-root .NET 容器

翻译自 Richard Lander 的博客 Rootless 或 non-root Linux 容器一直是 .NET 容器团队最需要的功能。我们最近宣布了所有 .NET 8 容器镜像都可以通过一行代码配置为 non-root 用户。今天的文章将介绍如何使用 Kubernetes 处理 non-root 托管。 您可以尝试使用我们的 non-root…

gateway报 netty堆外内存溢出问题解决io.netty.util.internal.OutOfDirectMemoryError

昨天线上网关突然无法访问。打开日志看到错误信息“io.netty.util.internal.OutOfDirectMemoryError” 堆外内存溢出。。这也没碰到过啊&#xff0c;看来今天准点下班的愿望又落空了。老规矩面向百度编程。先看看网上有没有其他兄弟碰到这个问题。一顿搜索之后发现&#xff0c;…

已解决windows pycocotools安装失败问题 —— 超简单

作者主页&#xff1a;爱笑的男孩。的博客_CSDN博客-深度学习,YOLO,活动领域博主爱笑的男孩。擅长深度学习,YOLO,活动,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typecollect个人…

分库分表与分布式主键生成策略详解--一个无数人踩过却一直被人忽视的深坑

文章目录 一、从分库分表的一个神坑说起二、分布式主键要考虑哪些问题&#xff1f;三、主要的主键生成策略1、数据库策略2、应用单独生成3、第三方服务统一生成4、与第三方结合的segment策略 四、定制雪花算法1、如影随形的时钟回拨问题2、用主键生成策略优化分配工作进程位3、…

萤石“小步快走”,跨进智能家居生态圈

文丨智能相对论 作者丨Kinki 近日&#xff0c;萤石网络&#xff08;下称“萤石”&#xff09;举办了2023春季新品发布会&#xff0c;这是公司上市以来的首个新品发布会&#xff0c;除了拳头产品智能家居摄像机之外&#xff0c;还有智能入户产品、TV Studio等十多款新品&#…

NC65 集团业务参数 GLS01参数值的默认值作用是什么?

NC65 集团业务参数 GLS01参数值的默认值作用是什么&#xff1f; 用在总账系统的所有账簿。如果设置的期间个数大于12&#xff0c;还得要求所查询的账表支持跨年查询&#xff0c;比如科目余额表&#xff0c;不支持跨年&#xff08;注意&#xff1a;这里说的不支持跨年是指余额为…

4.2.1朴素模式匹配算法

什么是字符串的模式匹配&#xff1a; 从这段字符串里面搜索内容&#xff0c;被搜索的字符串我们称之为主串。 也可能匹配不到 主串长度为n&#xff0c;模式串长度为m。 朴素模式匹配算法&#xff1a;将主串中所有长度为m的字串依次与模式串对比&#xff0c;直到找到一个完全匹…

【JavaEE】File、InputStream和OutputStream的使用

1.File 在计算机中目录结构如下&#xff1a; 而File就表示一个目录或者一个普通文件。 File表示目录&#xff1a; File表示普通文件&#xff1a; 我们先来看File的构造方法&#xff1a; 构造器描述File(File parent, String child)根据父目录 孩子文件路径&#xff0c;创…

Linux权限提升—定时任务、环境变量、权限配置不当、数据库等提权

Linux权限提升—定时任务、环境变量、权限配置不当、数据库等提权 1. 前言1.1. 如何找编译好的EXP 2. 定时任务提权2.1. 查看定时任务2.2. 通配符注入提权2.2.1. 创建执行脚本2.2.2. 创建定时任务2.2.3. 查看效果2.2.4. 提权操作2.2.4.1. 切换普通用户2.2.4.2. 执行命令2.2.4.3…

优先、双端队列-我的基础算法刷题之路(八)

本篇博客旨在整理记录自已对优先队列、双端队列的一些总结&#xff0c;以及刷题的解题思路&#xff0c;同时希望可给小伙伴一些帮助。本人也是算法小白&#xff0c;水平有限&#xff0c;如果文章中有什么错误之处&#xff0c;希望小伙伴们可以在评论区指出来&#xff0c;共勉 &…

Netty 源码解析(下)

接上一篇博客 Netty 源码解析&#xff08;上&#xff09;继续分析 上一篇博客中已经分析了绝大部分 ChannelFuture cf bootstrap.bind(9000).sync(); 这一行代码&#xff0c;当这一行代码运行完时&#xff0c;Netty服务端就已经启动好了&#xff0c;接下来就是接收链接&#x…

Spring Security OAuth2.0(二)-----简化模式/密码模式/客户端模式/刷新 token

简化模式 代码示例 修改authorization_server授权服务模块 新增“implicit” 和修改回调地址为本次地址 修改第三方应用项目搭建新页面模拟 新建implicit.jsp <% page contentType"text/html;charsetUTF-8" language"java" isELIgnored"fals…

C++入门篇(二)

目录 一、引用1.1 什么是引用&#xff1f;1.2 引用的特性1.3 常引用1.4 引用的使用场景1.5 传值和传引用效率比较1.5.1 传值和传引用做参数的性能对比1.5.2 传值和传引用做返回值的性能对比 1.6 引用和指针之间的区别 二、内联函数2.1 什么是内联函数&#xff1f;2.2 内联函数的…

知识变现海哥|研究了100个项目,这个才是人生逆袭首选

&#xff08;本文源自公号跟海哥学知识变现&#xff0c;移步公号与100万知识变现/知识付费创业者&#xff0c;一起学知识变现知识付费干货&#xff0c;回‘领书’获取3本电子书&#xff1a;【知识付费秘籍】【知识创业者成长手册】【100个知识付费成功案例】) 经常有人问海哥&a…

什么是中断向量表?作用是什么?为什么需要偏移?

一、定义与特点 定义&#xff1a;中断向量表(interrupt vector table)包含中断服务程序地址的特定内存区域&#xff0c;这些服务程序是处理外部硬件中断请求的代码。 特点&#xff1a;这些中断服务程序(函数)在中断向量表中的位置是由半导体厂商定好的&#xff0c;当某个中断…

ESP32-C2开发板 Homekit烧录教程

准备 1.1硬件ESP32 C2开发板&#xff0c;如图1-1所示 图1-1 ESP32 C2开发板 1.2软件 CozyLife APP可以在各大应用市场搜索下载&#xff0c;也可以扫描二维码下载如图1-2所示 HomeKit flash download tool 烧录工具 esp32c2 homkit演示固件 烧录教程 打开flash_download_to…

以智求治,MapGIS打造公共安全治理新模式

随着我国城市人口和规模日益扩大&#xff0c;城市运行系统日趋复杂&#xff0c;各类风险隐患增多且呈现相互叠加、相互耦合态势&#xff0c;各类风险、事故灾害类事件造成的损失严重&#xff0c;公共安全防范压力不断增大。 党的二十大报告中指出&#xff1a;“建立大安全大应…