linux网络编程、socket编程

进程间通信:
特点:依赖于内核,造成缺陷——无法实现多机通信。

网络:
地址:由IP地址(IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。)和端口号构成(所谓的端口,就好像是门牌号一样,客户端可以通过ip地址找到对应的服务器端,但是服务器端是有很多端口的,每个应用程序对应一个端口号,通过类似门牌号的端口号,客户端才能真正的访问到该服务器。为了对端口进行区分,将每个端口进行了编号,这就是端口号 ,端口包括逻辑端口和物理端口两种类型),实际上是通过IP地址+端口号来区分不同服务的,端口号提供了一种访问通道,服务器一般都是通过知名端口号来识别的。例如:对于每个TCP/IP实现来说,FTP服务器的TCP端口号就是21,每个Talnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69.

数据交流:
当涉及到数据交流的时候就会涉及到协议(说白了就是数据格式),例如:http(超文本传输协议是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII形式给出;而消息内容则具有一个类似MIME的格式。这个简单模型是早期Web成功的有功之臣,因为它使开发和部署非常地直截了当。)、tcp(传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。)、udp(Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。RFC 768描述了 UDP。)

socket套接字:

  • 所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口。
  • 所谓socket网络编程,也叫作套接字网络编程,套接字网络编程用到的协议TCP协议和UDP协议的用的比较多。

TCP和UDP协议的区别:

  • 连接方面区别:TCP提供面向连接的传输,通信前要先建立连接(三次握手机制)(如打电话要先拨号建立连接)。UDP是无连接的,面向报文的,即发送数据之前不需要建立连接。
  • 安全方面的区别:TCP提供可靠的服务,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达。UDP尽最大努力交付,即不保证可靠交付。
  • 传输效率的区别:TCP传输效率相对较低。UDP传输效率高,适用于对高速传输和实时性有较高的通信或广播通信。
  • 连接对象数量的区别:TCP连接只能是点到点、一对一的。UDP支持一对一,一对多,多对一和多对多的交互通信。
  • TCP首部开销20字节,UDP的首部开销小,只有8个字节

字节序:
字节序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。计算机硬件有两种储存数据的方式:大端字节序(big endian)和小端字节序(little endian)。

为什么会有小端字节序?

  • 计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的。所以,计算机的内部处理都是小端字节序。
  • 但是,人类还是习惯读写大端字节序。所以,除了计算机的内部处理,其他的场合几乎都是大端字节序,比如网络传输和文件储存。

常见序:

  • Little endian(小端字节序):将低序字节存储在起始地址
  • Big endian(大端字节序):将高序字节存储在起始地址
  • 网络协议指定了通讯字节序—大端
  • 只有在多字节数据作为整体处理时才需要考虑字节序
  • 运行在同一台计算机上的进程相互通信时,一般不用考虑字节序
  • 异构计算机之间通讯,需要转换自己的字节序为网络字节序

什么是高低位:

  • 给一个十进制整数,123456,很明显左边的是高位,右边的是低位。计算机也是这样认为的。给一个16进制数(四个二进制表示),0x12345678,以字节为单位,从高位到低位依次是 0x12、0x34、0x56、0x78。
  • 例子:在内存中双字0x01020304(DWORD)的存储方式
    地址从低到高:4000->4001->4002->4003
    小端字节序: 04 03 02 01
    大端字节序:01 02 03 04

socket编程步骤:

可以把服务器与客户端之间的场景看做以下场景:一个客户端走到五座房子(5个服务器)的面前,要访问这五座房子中的一座房子中的一间房间。当客户端不知道去哪一间房子时,这时候有一个人在楼上喊我是说汉语的(TCP/UDP)服务器,我的楼号是…(IP地址),我的房间号是…(端口号),然后客户端就可以获取服务器IP和服务器端口号进行连接。

在这里插入图片描述

服务器端创建步骤:

  • 服务器端创建套接字(socket函数),返回网络描述符,后续用网络描述符进行操作
  • bind()为套接字添加信息,指定服务器自己的IP地址和端口号
  • 监听网络连接(listen()函数)
  • 监听到有客户端接入,接收一个连接(accept()函数)
  • 数据交互(利用read函数从网络上面读数据,利用write函数向网络上面写数据)
  • 关闭套接字(close()函数),断开连接

客户端创建步骤:

  • socket()创建一个通道
  • connect()连接服务器,根据IP地址和端口号
  • 然后进行读写操作
  • 最后关闭套接字断开连接

三次握手和一次挥手:
当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

socket编程函数介绍

socket()函数:

#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain, int type, int protocol);
功能:这个函数建立一个协议族为domain、协议类型为type、协议编号为protocol的套接字文件描述符。参数:domain:函数socket()的参数domain用于设置网络通信的域函数socket()根据这个参数选择通信协议的族,通常为AF_INET,表示互联网协议族(TCP/IP协议族)。通信协议族在文件sys/socket.h中定义。协议族决定了socket的地址类型,在通信中必须采用对应的地址domain的值及含义:AF_INET、PF_INET:      IPV4因特网域AF_INET6:              IPV6因特网域AF_UNIX:                Unix域AF_ROUTE:               路由套接字AF_KEY:                 密钥套接字AF_UNSPEC:              未指定PF_UNIX,PF_LOCAL:      本地通信type:指定socket类型常用的socket类型有:SOCK_STREAM:  Tcp连接,提供序列化的、可靠的、双向连接的字节流,使用TCP协议。支持带外数据传输SOCK_DGRAM:   数据报套接字定义了一种无连接的报,数据通过相互独立的报文件进行传输,是无序的,并且不保证是可靠的、无差错的、使用数据报协议UDP连接(无连接状态的消息)SOCK_RAW:     RAW类型,允许程序使用底层协议,原始套接字允许对底层协议如IP/ICMP进行直接访问,功能强大但使用较为不便,主要用于协议的开发SOCK_PACKET:  这是一个专用类型,不能呢过在通用程序中使用SOCK_SEQPACKET:序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统调用时数据需要将全部数据读出protocol:故名思意,就是指定协议.常用的协议有:IPPROTO_TCP:TCP传输协议IPPTOTO_UDP:UDP传输协议IPPROTO_SCTP:STCP传输协议IPPROTO_TIPC:TIPC传输协议返回值:如果函数调用成功,会返回一个标识这个套接字的文件描述符,失败的时候返回-1
  • 注意: 并不是上面的type和protocol可以随意组合的,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议。
  • 当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口。

bind()函数:

#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:正如上面所说bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。参数:sockfd:即socket描述字,它是通过socket()函数创建了唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址这个地址结构根据地址创建socket时的地址协议族的不同而不同。如ipv4对应的是: struct sockaddr{unsigned short as_familf;//协议族char sa_data[14];//IP+端口号}同等替换为:使用时,强转:(struct sockaddr *)&my_addr struct sockaddr_in {sa_family_t    sin_family; /* 协议族: AF_INET */in_port_t      sin_port;   /* 端口号,一般用5000以上,低于3000的是操作系统的关键端口,这个要将它转化为网络字节序*/struct in_addr sin_addr;   /* IP地址结构体*/unsigned char sin_zero[8]/*填充没有实际意义只是为跟sockaddr结构体在内存中对齐,这样两者才能相互转换*/};/* 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 */ };Unix域对应的是: #define UNIX_PATH_MAX    108struct sockaddr_un { sa_family_t sun_family;               /* AF_UNIX */ char        sun_path[UNIX_PATH_MAX];  /* pathname */ };addrlen:对应的是地址的长度,结构体大小。返回值:bind()函数的返回值为0时表示绑定成功,-1表示绑定失败
  • 通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。
  • 在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。请谨记对主机字节序不要做任何假定,务必将其转化为网络字节序再赋给socket。

IP地址转换API:

旧版本:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
功能:将点分十进制IP转化为网络字节序存放在addr中,并返回该网络字节序对应的整数。
参数:输入参数cp包含ASCII表示的IP地址。输出参数inp是将要用新的IP地址更新的结构。
返回值:如果这个函数成功,函数的返回值非零。如果输入地址不正确则会返回零。使用这个函数并没有错误码存放在errno中,所以他的值会被忽略。in_addr_t inet_addr(const char *cp);
功能:将点分十进制IP转化为网络字节序(二进制位的大端存储)。
返回值;如果失败:返回INADDR_NONE;如果成功:返回IP对应的网络字节序的数;char *inet_ntoa(struct in_addr in);
功能:把网络格式的ip地址转化为字符串形式
inet_network函数in_addr_t  inet_network(const char *StrIP)
功能: 将点分十进制IP转化为主机字节序(二进制位小端存储)。
返回值:如果失败:返回-1;如果成功:返回主机字节序对应的数;
旧版本的只能处理IPv4的ip地址
不可重入函数
注意参数是struct in_addr新版本:
#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);
新版本的支持IPv4和IPv6
可重入函数
其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,
还可以转换IPv6的in6_addr,因此函数接口是void *addrptr。

listen()、connect()函数:
如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。

#include<sys/types.h>
#include<sys/socket.h>
int listen(int sockfd, int backlog);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:内核为任何一个给定监听者套接字,维护两个队列:1、未完成队列,每个这样的SYN报文段对应其中一项已由某个客户端发出并到达服务器,而服务器正在等待相应的TCP三次握手过程,这些套接字处于SYN_REVD状态2、已完成队列,每个已完成TCP三次握手过程的客户端对应其中一项,这些套接字处于ESTABLISHED状态。参数:listen函数的第一个参数即为要监听的socket描述字服务器的描述字第二个参数为相应socket可以排队的最大连接个数。listen()并未开始连线,只是设置socket的listen模式。listen函数只用于服务器端。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。返回值:listen函数:成功返回0, 失败返回-1.connect函数:成功返回0, 失败返回-1.

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

#include<sys/types.h>
#include<sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,不关心可以设置为NULl。第三个参数为协议地址的长度。返回值:如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。失败时返回-1
  • 注意: accept的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept函数返回的是已连接的socket描述字。一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。

数据的收发:

一般用read/write函数,当然还有其他函数:

  • read/write
  • recv()/send()
  • readv()/writev()
  • recvmsg()/sendmsg()(多在UDP连接时使用)
  • recvfrom()/sendto()(多在UDP连接时使用)
#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);

recv()/send()函数:
在这里插入图片描述

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

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

网络字节序和主机字节序的转换:

#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<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
//#include<linux/in.h> 头文件之间可能造成冲突这个头文件就和#include <arpa/inet.h>冲突
#include <arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include <sys/wait.h>
#include<pthread.h>
struct num
{int fd;char*write;
};
void* writeMsg(void*arg)
{int i;struct num Part;Part.write=((struct num*)arg)->write;Part.fd=((struct num*)arg)->fd;while(1){if(i==1){getchar();}i=1;memset(Part.write,'\0',128);printf("输入要给客户端的内容:\n");scanf("%[^\n]",Part.write);write(Part.fd,Part.write,128);}
}
int main()
{struct sockaddr_in IP;struct sockaddr_in CLI;//客户端信息struct num CAN;int socketre;int bindre;int i=0;int newfd;pid_t fpid;pthread_t sontd;char* writebuf;char* readbuf;readbuf=(char*)malloc(128);writebuf=(char*)malloc(128);int len=sizeof(struct sockaddr_in);socketre=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(socketre==-1){printf("create fail\n");perror("socket");exit(-1);}memset(&IP,'\0',len);memset(&CLI,'\0',len);IP.sin_family=AF_INET;IP.sin_port=htons(8686);IP.sin_addr.s_addr=inet_addr("192.168.1.183");bindre=bind(socketre,(struct sockaddr*)&IP,len);if(bindre==-1){perror("bind");printf("bind fail\n");exit(-1);}listen(socketre,10);while(1){newfd=accept(socketre,(struct sockaddr*)&CLI,&len);if(newfd==-1){perror("accept");printf("accept fail\n");exit(-1);}printf("连接成功\n");printf("get client:%s\n",inet_ntoa(CLI.sin_addr));CAN.write=writebuf;CAN.fd=newfd;fpid=fork();if(fpid==0){pthread_create(&sontd,NULL,writeMsg,(void*)&CAN);while(1){memset(readbuf,'\0',128);if(read(newfd,readbuf,128)!=0){if(strcmp(readbuf,"quit")==0){write(newfd,"server is out",13);close(newfd);pthread_cancel(sontd);break;}printf("接受到消息:%s\n",readbuf);printf("输入要给客户端的内容:\n");}else{printf("与客户端断开连接\n");}}}if(fpid>0){waitpid(fpid,NULL,WNOHANG | WUNTRACED);}}return 0;
}

如果有手机的话可以下载TCP手机助手,进行连接服务器,没有该软件可以用以下客户端代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include<pthread.h>
struct Client
{char* write;int fd;
};
void* del(void*arg)
{struct Client CAN;CAN.write=((struct Client*)arg)->write;CAN.fd=((struct Client*)arg)->fd;while(1){memset(CAN.write,'\0',128);printf("请输入要发送给服务端的消息:\n");scanf("%s",CAN.write);write(CAN.fd,CAN.write,strlen(CAN.write));}
}
int main()
{int socketfd;int conre;char*writebuf;char*readbuf;pthread_t th;struct Client CL;struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(8686);addr.sin_addr.s_addr=inet_addr("192.168.1.183");socketfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(socketfd==-1){printf("socket create fail\n");perror("socket");exit(-1);}conre=connect(socketfd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));if(conre==-1){printf("connect fail\n");perror("connect");exit(-1);}writebuf=(char*)malloc(128);readbuf=(char*)malloc(128);CL.write=writebuf;CL.fd=socketfd;pthread_create(&th,NULL,del,(void*)&CL);while(1){memset(readbuf,'\0',128);read(socketfd,readbuf,128);printf("获取到服务端数据:%s\n",readbuf);printf("请输入要发送给服务端的消息:\n");}return 0;
}

补充:

  • 当我们想用一个结构体或者联合体时,可以进入/usr/include/这个文件夹下面,查找看看头文件里面有没有包含想要使用的结构体或者联合体,使用以下命令:
cd /usr/include/
进入文件夹
grep "struct sockaddr_in {" * -nir
grep表示查找,双引号内的东西是你要查找的内容的一部分
*表示在当前目录下。-nir中 n表示显示行号,i表示不区分大小写,r表示逐行扫描
linux/in.h:232:struct sockaddr_in {
得到结果:232表示行号,linux/in.h表示所在文件夹
vi linux/in.h  +232
这个命令是直接打开定位到该文件的232行。
  • linux查看端口号占用命令-netstat
netstat -pan | grep 5623
#其中5623位端口号

在这里插入图片描述如图:可以看到占用该端口号的进程,并且可以利用ps指令找到程序名称。

判断socket有没有与客户端断开连接

本文参照博客:socket编程

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

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

相关文章

Linux文件和目录权限笔记

查看文件或者目录的权限命令&#xff1a;ls -al # -a 表示全部文件包含隐藏文件&#xff0c;-l 表示列出每个文件的详细信息比如执行 ls -altotal 115drwxr--x--- 4 root root 4096 Oct 24 02:07 install.log格式说明&#xff1a;通过 ls -al 格式化输出的文件详细信息&#x…

python基础:序列(列表、元组、字符串)、函数、字典、集合

Python语言运行环境&#xff1a; windowslinuxunixMacos等等 博客记录内容&#xff1a; Python3的所有语法、面向对象思维、运用模块进行编程、游戏编程、计算机仿真。 Python是什么类型的语言&#xff1a; Python是脚本语言&#xff0c;脚本语言(Scripting language)是电脑…

python基础(文件、异常、模块、类、对象)

文件&#xff1a; 打开文件使用open函数&#xff0c;open()的第一个参数是&#xff1a;要打开文件的路径&#xff0c;如果只传入文件名那么将在当前文件下查找文件并打开。第二个参数是&#xff1a;文件的打开模式&#xff0c;其他参数都是默认的。文件的打开模式如下图所示&a…

redis 和 memcached 的区别

redis 和 memcached 的区别 对于 redis 和 memcached 我总结了下面四点。现在公司一般都是用 redis 来实现缓存&#xff0c;而且 redis 自身也越来越强大了&#xff01; redis支持更丰富的数据类型&#xff08;支持更复杂的应用场景&#xff09;&#xff1a;Redis不仅仅支持简…

树莓派入门(树莓派登录的几种方式)

什么是嵌入式&#xff1f; 嵌入式即嵌入式系统&#xff0c;IEEE&#xff08;美国电气和电子工程师协会&#xff09;对其定义是用于控制、监视或者辅助操作机器和设备的装置&#xff0c;是一种专用的计算机系统。国内普遍认同的嵌入式系统定义是以应用为中心&#xff0c;以计算…

Linux库概念及相关编程(动态库、静态库、环境变量)

分文件编程&#xff1a; 好处&#xff1a;分模块编程思想&#xff0c;功能和责任划分清楚便与调试&#xff0c;main函数简洁&#xff0c;代码易于阅读。编程时头文件有的是使用<>这个符号括起来的&#xff0c;有的是" "使用的是双引号&#xff0c;使用尖括号括…

kali扫描内网ip_Metasploit路由转发实现内网渗透

利用背景在渗透的过程中常常会遇到这种场景&#xff1a;我们已经通过web渗透拿下一台内网服务器&#xff0c;为了进一步进行内网渗透&#xff0c;我们会利用“沦陷主机”作为跳板进行进一步的内网渗透&#xff0c;扩大战果。现在假设的场景是此时我们已经拿下一台内网服务器的远…

.NET Core 3.0 中的新变化

译者&#xff1a;楚人Leo译文&#xff1a;http://www.cnblogs.com/leolion/p/10585834.html原文&#xff1a;https://msdn.microsoft.com/en-us/magazine/mt848631.aspx.NET Core 3.0 是 .NET Core 平台的下一主要版本。本文回顾 .NET Core 发展历史&#xff0c;并展示了它是如…

树莓派GPIO口的使用(外设相关开发WringPi库的使用,超声波、继电器)

树莓派的接口&#xff1a; 大而简单的类别&#xff1a;IO口&#xff0c;input和output是相对于主控芯片来说的&#xff0c;是根据MCU和外设之间的关系将IO口的功能分为output和input。当IO作为input使用时外设有&#xff1a;人体传感器、烟雾传感器、火焰传感器、振动传感器等…

volatile指令重排_有多少人面试栽到Volatile上?面试问题都总结到这儿了

Volatile关键字volatile 是Java虚拟机提供的 轻量级 的同步机制.何为 轻量级 呢&#xff0c;这要相对于 synchronized 来说。Volatile有如下三个特点。要搞清楚上面列举的名词 可见性 原子性 指令重排 的含义我们需要首先弄清楚JMM(Java内存模型是怎么回事)JMM规定了内存主要划…

Dubbo核心概念

节点角色规范 节点角色规格Provider提供者公开远程服务Consumer消费者致电远程服务Registry注册表负责服务发现和配置Monitor监视器计算服务调用的数量和耗时Container容器管理服务的生命周期 服务关系 Container负责启动&#xff0c;加载和运行服务Provider。ProviderRegiste…

良心推荐11款可以称得上“神器”的Windows工具集合

1、最快文件搜索工具 Everything&#xff1a;当之无愧的最强本地文件搜索神器&#xff0c;搜索任何关键词基本是秒速出现&#xff0c;比Windows自带的搜索快了太多&#xff0c;电脑文件比较多的人必备&#xff01; 2、专业软件卸载器 Revo Uninstaller Pro&#xff1a;Windows电…

LD3320语音识别模块二次开发及与树莓派间的通讯

实物图如下&#xff1a; 一般这种模块的资料厂家都会给&#xff0c;需要的话可以私信我发邮箱&#xff0c;下面介绍该模块的各种参数。型号&#xff1a;YS-LDV7名称&#xff1a;一体化语音识别模块规格&#xff1a;43*29.7MM供电电压&#xff1a;5V &#xff08;内部工作电压…

多生产者_你是生产者还是消费者?这决定了你的层次。

不知道你有没有注意到&#xff0c;每天乘坐地铁上下班的时候&#xff0c;大部分人都在刷剧、看视频、打游戏等等&#xff0c;总之都属于玩乐。用生产和消费的关系来看的话&#xff0c;其实这一大部分人都属于消费者&#xff0c;“时间和注意力”是他们用于交换的筹码&#xff1…

eclipse Android 开发基础 Activity 窗体 界面

eclipse Android 开发基础 新建工程 新建布局layout,new Android Activity就相当于窗体Form。 新建Activity自动生成src下同名的java代码。 public class Tform2activity extends Activity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(saved…

8 种常被忽视的 SQL 错误用法

来源&#xff1a;http://t.cn/R6UMaA11、LIMIT 语句2、隐式转换3、关联更新、删除4、混合排序5、EXISTS语句6、条件下推7、提前缩小范围8、中间结果集下推总结sql语句的执行顺序&#xff1a;FROM <left_table>ON <join_condition><join_type> JOIN <right…

变频器按启动没反应_起重机软启动柜晶闸管损坏维修几大故障

缺相保护功能&#xff1a;工作时&#xff0c;软起动器随时检测三相线电流的变化&#xff0c;一旦发生断流&#xff0c;即可作出缺相保护反应。过热保护功能&#xff1a;通过软起动器内部热继电器检测晶闸管散热器的温度&#xff0c;一旦散热器温度超过允许值后自动关断晶闸管&a…

Redis 的各项功能解决了哪些问题?

作者丨blackheart先看一下Redis是一个什么东西官方简介解释到&#xff1a;Redis是一个基于BSD开源的项目&#xff0c;是一个把结构化的数据放在内存中的一个存储系统&#xff0c;你可以把它作为数据库&#xff0c;缓存和消息中间件来使用。同时支持strings&#xff0c;lists&am…