首页 > 其他分享 >APUE-网络socket通信

APUE-网络socket通信

时间:2024-01-14 22:22:55浏览次数:27  
标签:serv addr int APUE 通信 fd printf socket

网络通信

​ 大部分网络应用系统可分为两部分:客户(Client)和服务器(Server),网路服务程序架构又两种:CS模式和BS模式。

CS:Client/Server(客户机/服务器)结构,特点:交互性强,具有安全的存取模式,网络通信量低,响应速度快,利于处理大量数据。

BS:Browser/Server(浏览器/服务器)结构,特点:分布性强,维护方便,开发简单且共享性强,总体拥有成本低。

OSI七层模型

OSI模型,即开放式通信系统互联参考模型(Open System Interconnection Reference Model),是国际标准化组织(ISO)提出的一个试图使各种计算机在世界范围内互连为网络的标准框架,简称OSI。

数据在网络中传输的过程实际是封装和解封装的过程,发送方通过各种封装处理,把数据转换成比特流的形式,比特流在信号传输的硬件媒介中传输,接收方再把比特流进行解封装处理。


TCP/IP协议

TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇,简称TCP/IP协议。

ping命令使用ICMP协议

ip地址在网络层,mac地址在物理层

地址解析协议:

ARP协议:将ip地址翻译为mac地址

RARP协议:将mac地址翻译为ip地址

网络接口层

  1. 数据封装/解封装成帧,帧中包括了需要传输的数据,发送方和接收方的物理地址(mac地址)以及检错和控制信息。
  2. 控制帧传输
  3. 流量控制,控制发送的速度

网络层

IP协议是TCP/IP协议簇中最核心的协议,所有TCP、UDP、ICMP、IGMP协议数据都以IP数据报格式传输。IP协议提供的是不可靠的、无连接的数据传输服务。

IP头默认20个字节

传输层

从传输层向更底层看,各层的协议都是直接或间接的服务于主机于主机之间的通信,而传输层是在进程与进程通信层面上的,传输层有两个重要的协议:TCP(传输控制协议)和UDP(用户数据报协议)。

UDP协议

用户数据报协议,优点:快,缺点:不可靠、不稳定

  • 无连接,发送之前不需要建立连接(TCP需要),减少延时和开销
  • 面向报文,对IP数据只做简单的封装(8字节报头),减少开销
  • 没有阻塞机制,宁愿阻塞时丢弃数据不传,也不阻塞造成延时
  • 支持一对一、一对多、多对一、多对多通信

TCP协议

传输控制协议,面向连接、提供可靠的数据传输服务(20字节报文头)。

  • 使用前需要进行”三次握手“建立连接,通信结束后还要使用”四次挥手“断开连接。
  • 点对点的连接,一条TCP连接只能连接两个端点
  • 提供可靠传输,无差错、不丢失、不重复、按顺序
  • 提供全双工通信,允许通信双方任何时候都能发送数据,发送方设有发送缓存,接收方有接收缓存
  • 面向字节流

应用层

常见端口:

端口号 名称 说明
20 ftp-data FTP数据端口
21 ftp 文件传输协议(FTP)控制端口
22 ssh 安全Shell远程登录服务
23 telnet Telnet远程登录服务
25 smtp 简单邮件传输协议(STMP)
53 dns 域名服务
69 tftp 简单文件传输协议
80 http 用于万维网(www)服务的超文本传输协议
123 ntp 网络时间协议
161/162 snmp 简单网络管理协议
443 https 安全超文本传输协议
1433 mysql 数据库服务程序默认端口
8080 tomcat java服务程序默认端口

端口号是16位,因此端口号的范围是065535,其中11024是被RFC3232规定好的,监听该范围端口程序必须以root权限运行;1025~65535的端口被称为动态端口,写服务器程序时,一般使用该范围内的端口。可以使用netstat命令查看当前主机上运行了哪些服务程序并监听了哪些端口。

一个TCP的网络连接中包含一个四元组:源IP、目的IP、源端口和目的端口。

socket编程

socket通信简介

网络层的”IP地址“可以唯一标识网络中的主机,而传输层的”端口“可以唯一标识主机中的应用程序。这样通过IP地址和端口就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其他进程进行交互。使用TCP/IP协议的应用程序通常采用应用编程接口:UNIX BSD的套接字(socket)来实现网络进程之间的通信。

socket是应用层与TCP/IP协议簇通信的中间软件抽象层。

应用程序要为因特网通信建立一个socket时,操作系统就返回一个小整数作为描述符来标识这个套接字。应用程序以改描述符作为传递参数,通过调用相应函数来完成操作。

socket通信基本流程:

socket服务器和客户端代码

服务器代码

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>


#define LISTEN_PORT
#define BACKLOG

int main(int argc, char *argv[])
{
        int                     rv = -1;
        int                     listen_fd, client_fd = -1;
        struct sockaddr_in      serv_addr,cli_addr;
        socklen_t               cliaddr_len = 1;
        char                    buf[1024];

        listen_fd = socket(AF_INET,SOCK_STREAM,0);
        if( listen_fd < 0 )
        {
                printf("creat socket failure: %s\n",strerror(errno));
                return -1;
        }
        printf("socket creat fd[%d]\n",listen_fd);

        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;	//sin_family指定ipv4还是ipv6
        serv_addr.sin_port = htons(LISTEN_PORT);	//sin_port指定端口,htons将主机字节序转为网络字节序
    	/*要监听的IP,INADDR_ANY即监听所有IP,如果要监听某个IP,用inet_aton()函数转为四字节整数形式,一般用宏*/
    	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);	
    	/*(struct sockaddr *)&serv_addr结构体类型强制转换,将sockaddr_in转为sockaddr ,sin_port和sin_addr都放在sa_data[14]中 */
        if( bind(listen_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0 )	
        {
                printf("creat socket failure: %s\n",strerror(errno));
                return -2;
        }
        printf("socket [%d] bind on port [%d] for all IP address ok\n",listen_fd,LISTEN_PORT);

        listen(listen_fd,BACKLOG);	//把主动的socket变为被动的

		while(1)
        {
                printf("Start waiting and accept new client connect...\n",listen_fd);
                client_fd = accept(listen_fd,(struct sockaddr*)&cli_addr,&cliaddr_len); //如果不需要ip和端口则传NULL
                if( client_fd < 0 )
                {
                        printf("accept new socket failure: %s\n",strerror(errno));
                        return -3;
                }
                printf("accept new client[%s:%d] with fd[%d]\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),client_fd);

                memset(buf,0,sizeof(buf);
                if( (rv = read(clien_fd,buf,sizeof(buf))) < 0 )	//< 0出错
                {
                        printf("read data from client socket[%d] failure:%s\n",client_fd,strerror(errno));
                close(client_fd);
                continue;
                }
                else if( rv == 0)	//=0说明断开连接
                {
                        printf("client socket[%d] disconnected\n",client_fd);
                        close(client_fd);
                        continue;
                }
                printf("read %d bytes data from client[%d] and echo it back:'%s'\n",rv,client_fd,buf);

                if( write(client_fd,buf,rv) < 0 )
                {
                        printf("write %d bytes data back to client[%d] failure: %s\n",rv,client_fd,strerror(errno));
                        close(client_fd);
                }

                sleep(1);
                close(client_fd);
        }
        close(listen_fd);


        return 0;
}

客户端代码

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_IP       "127.0.0.1"
#define SERVER_PORT     8889
#define MSG_STR         "Hello World!"

int main(int argc,char *argv[])
{
        int                     conn_fd = -1;
        int                     rv = -1;
        char                    buf[1024];
        struct sockaddr_in      serv_addr;

        conn_fd = socket(AF_INET,SOCK_STREAM,0);
        if( conn_fd < 0 )
        {
                printf("creat socket failure: %s\n",strerror(errno));
                return -1;
        }
        printf("soket creat fd[%d]\n",conn_fd);

        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(SERVER_PORT);
    	/*127.0.0.1是点分十进制的字符串,用inet_aton转为四字节整数形式*/
        inet_aton(SERVER_IP,&serv_addr.sin_addr);	
    
        if(connect(conn_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        {
                printf("connect to server [%s:%d] failure: %s\n",SERVER_IP,SERVER_PORT,strerror(errno));
                return -2;
        }

        if( write(conn_fd,MSG_STR,strlen(MSG_STR)) < 0 )
        {
                printf("write data to server [%s:%d] failure: %s\n",SERVER_IP,SERVER_PORT,strerror(errno));
                close(conn_fd);
        }

 		memset(buf,0,sizeof(buf));
        rv = read( conn_fd,buf,sizeof(buf));
        if(rv < 0)
        {
                printf("read data from server faliure: %s\n",strerror(errno));
                close(conn_fd);
        }
        else if( 0 == rv )
        {
                printf("server disconnected\n");
                close(conn_fd);
        }

        printf("read %d bytes data from server: '%s'\n",rv,buf);

        return 0;
}

li@Raspberrypi4B:~ $ ./socket_server
socket creat fd[3]
socket [3] bind on port [8889] for all IP address ok
Start waiting and accept new client connect...
accept new client[16.4.1.0:15862] with fd [4]
read 12 bytes data from client[4] and echo it back:'Hello World!'
Start waiting and accept new client connect...
li@Raspberrypi4B:~ $ ./socket_client
soket creat fd[3]
read 12 bytes data from server: 'Hello World!'

socket()函数

int socket(int doamin,int type,int protocol);

Socket()用于创建一个socket描述符,标识一个socket。

  • domain:协议域,决定了socket的地址类型,如 AF_INET要用IPV4地址与端口号
  • type:指定socket类型,常见类型:SOCK_STREM(TCP),SOCK_DGRAM(UDP)
  • protocol:指定协议,一般默认为0即可,0可以根据第二参数自动匹配相应的协议

bind()函数

int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
  • sockfd:socket描述符
  • addr:sockaddr 类型的指针,储存地址和端口。存储IPv4的结构体类型为:struct sockaddr_in,存储IPv6的结构体类型为:struct sockaddr_in6
  • addrlen:地址长度

listen()函数

int listen(int sockfd,int backlog);
  • sockfd:要监听的socket描述字
  • backlog:相应socket可以排队的最大连接数

accept()函数

int accept(int sockfd,struct sockaddr *addr,socklen_t addrlen)
  • sockfd:监听socket描述字
  • addr:struct sockaddr*类型的指针
  • addrlen:地址长度
  • 返回值:一个新的描述符用于和客户端通信

connect()函数

int connect(int sockfd,struct sockaddr *addr,socklen_t addrlen)
  • sockfd:客户端的socket描述字
  • addr:服务器的socket地址
  • addrlen:socket地址长度

新型网路地址转化函数inet_pton和inet_ntop

​ 在此前的代码中我们使用的inet_aton()或inet_ntoa()函数完成IPv4点分十进制字符串和32位整形数据之间的互相转换,但这两个函数只适合于IPv4的地址。下面这两个函数可以同时兼容IPv4和IPv6的地址:

//将点分十进制的ip地址转化为用于网络传输的数值格式,返回值:若成功则为1,若输入不是有效的表达式则为0,若出错则为-1
int inet_pton(int family, const char *strptr, void *addrptr); 
 
//将数值格式转化为点分十进制的ip地址格式,返回值:若成功则为指向结构的指针,若出错则为NULL
const char * inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

close()和shutdown()函数

int close(int fd);

对socket fd调用close()会触发TCP连接断开的四路挥手。

int shutdown(int sockfd,int how);

shutdown()函数可以半关闭套接字。

how值:

  • SHUT_RD:不可再读入数据
  • SHUT_WR:不可再写入数据
  • SHUT_RDWR:既不可读,也不可写

getopt()和getopt_long()函数

命令行参数

命令行参数可以分为两类,一类是短选项,一类是长选项,短选项在参数前加一杠"-",长选项在参数前连续加两杠"–",如下表(ls 命令参数)所示,其中-a,-A,-b都表示短选项,–all,–almost-all, --author都表示长选项。他们两者后面都可选择性添加额外参数。比如–block-size=SIZE,SIZE便是额外的参数。例如:

LS(1)                            User Commands                           LS(1)

NAME
       ls - list directory contents

SYNOPSIS
       ls [OPTION]... [FILE]...

DESCRIPTION
       List  information  about  the FILEs (the current directory by default).
       Sort entries alphabetically if none of -cftuvSUX nor --sort  is  speci‐
       fied.

       Mandatory  arguments  to  long  options are mandatory for short options
       too.

       -a, --all
              do not ignore entries starting with .

       -A, --almost-all
              do not list implied . and ..

       --author
              with -l, print the author of each file

       -b, --escape
              print C-style escapes for nongraphic characters

       --block-size=SIZE
              scale sizes by SIZE before printing them; e.g., '--block-size=M'
              prints sizes in units of 1,048,576 bytes; see SIZE format below

       -B, --ignore-backups
              do not list implied entries ending with ~

getopt_long函数

getopt函数只能处理短选项,而getopt_long函数两者都可以

#include <unistd.h>  
extern char *optarg;  
extern int optind, opterr, optopt;  
#include <getopt.h>
int getopt(int argc, char * const argv[],const char *optstring);  
int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);  
int getopt_long_only(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);

1、argc和argv和main函数的两个参数一致。

2、optstring: 表示短选项字符串。

形式如“a​ : b : : cd“,分别表示程序支持的命令行短选项有-a、-b、-c、-d,冒号含义如下:

只有一个字符,不带冒号——只表示选项, 如-c

一个字符,后接一个冒号——表示选项后面带一个参数,如-a 100

一个字符,后接两个冒号——表示选项后面带一个可选参数,即参数可有可无, 如果带参数,则选项与参数之间不能有空格,形式应该如-b200

3、longopts:表示长选项结构体。结构如下:

struct option opts[] = {
                {"ipaddr", required_argument, NULL, 'i'},
                {"prot", required_argument, NULL, 'p'},
                {"help", no_argument, NULL, 'h'},
                {0, 0, 0, 0}
        };

服务器和客户端代码2

客户端

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <getopt.h>


#define MSG_STR "Hello World!"

void print_usage(char *progname)
{
        printf("%s usage: \n",progname);
        printf("-i(--ipaddr): sepcify server IP address.\n");
        printf("-p(--port): sepcify server port.\n");
        printf("-h(--help): print this help information.\n");

        return ;
}

int main(int argc,char *argv[])
{
        int                     conn_fd = -1;
        int                     rv = -1;
        char                    buf[1024];
        struct sockaddr_in      serv_addr;
        char                    *serv_ip =  NULL;
        int                     port = 0;
        int                     opt = -1;
        const char              *optstring = "i:p:h";
        struct option           opts[] = {
                {"ipaddr", required_argument, NULL, 'i'},
                {"prot", required_argument, NULL, 'p'},
                {"help", no_argument, NULL, 'h'},
                {NULL, 0, NULL, 0}
        };

        while ( (opt = getopt_long(argc, argv, optstring, opts, NULL)) != -1 )
        {
                switch (opt)
                {
                        case 'i':
                                serv_ip = optarg;
                                break;
                        case 'p':
                                port = atoi(optarg);
                                break;
                        case 'h':
                                print_usage(argv[0]);
                                return 0;
                }
        }

        if( !serv_ip || !port )
        {
                print_usage(argv[0]);
                return 0;
        }

        conn_fd = socket(AF_INET,SOCK_STREAM,0);
        if( conn_fd < 0 )
        {
                printf("Creat socket failure: %s\n",strerror(errno));
                return -1;
        }
        printf("Soket creat fd[%d] successfully\n",conn_fd);

        // 初始化结构体,将空余的8位字节填充为0
    	// 设置参数,connect连接服务器
        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(port);
        inet_aton(serv_ip,&serv_addr.sin_addr);

        rv = connect( conn_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr) );
        if(rv < 0)
        {
                printf("Connect to server [%s:%d] failure: %s\n",serv_ip,port,strerror(errno));
                return -2;
        }
        printf("Connect to server [%s:%d] successfully!\n",serv_ip,port);

        while(1)
        {
            // 每次进入循环清空缓冲区
        	// 持续读取服务器发送的数据存入缓冲区
                rv = write(conn_fd,MSG_STR,strlen(MSG_STR));
                if( rv < 0 )
                {
                        printf("Write data to server [%s:%d] failure: %s\n",serv_ip,port,strerror(errno));
                        break;
                }

                memset(buf,0,sizeof(buf));
                rv = read( conn_fd,buf,sizeof(buf) );
                if(rv < 0)
                {
                        printf("Read data from server by sockfd[%d] faliure: %s\n",conn_fd,strerror(errno));
                        break;
                }
                else if( 0 == rv )
                {
                        printf("Sockfd[%d] get disconnected\n",conn_fd);
                        break;
                }
                else if( rv > 0 )
                {
                        printf("Read %d bytes data from server: '%s'\n",rv,buf);
                }
        }

        close(conn_fd);

        return 0;
}

服务器端

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <getopt.h>


#define MSG_STR "Hello World!"
#define MAX_CLIENT 5

void print_usage(char *progname)
{
        printf("%s usage: \n",progname);
        printf("-p(--port): sepcify server port.\n");
        printf("-h(--help): print this help inforation.\n");

        return ;
}

int main(int argc,char *argv[])
{
        int                     sock_fd = -1;
        int                     client_fd = -1;
        int                     rv = -1;
        char                    buf[1024];
        struct sockaddr_in      serv_addr;
        struct sockaddr_in      cli_addr;
        socklen_t               cliaddr_len;
        int                     port = 0;
        int                     on = 1;
        int                     opt = -1;
        const char              *optstring = "p:h";
        struct option           opts[] = {
                {"prot", required_argument, NULL, 'p'},
                {"help", no_argument, NULL, 'h'},
                {NULL, 0, NULL, 0}
        };

        while ( (opt = getopt_long(argc, argv, optstring, opts, NULL)) != -1 )
        {
                switch (opt)
                {
                        case 'p':
                                port = atoi(optarg);
                                break;
                        case 'h':
                                print_usage(argv[0]);
                                return 0;
                }
        }

        if( !port )
        {
                print_usage(argv[0]);
                return 0;
        }

        sock_fd = socket(AF_INET,SOCK_STREAM,0);
        if( sock_fd < 0 )
        {
                printf("Creat socket failure: %s\n",strerror(errno));
                return -1;
        }
        printf("Soket creat fd[%d] successfully\n",sock_fd);

    	//解决Address already in use 的问题
        setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(port);
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        rv = bind( sock_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr) );
        if(rv < 0)
        {
                printf("Socket[%d] bind on port [%d] failure: %s\n",sock_fd,port,strerror(errno));
                return -2;
        }
        printf("Socket[%d] bind on port [%d]successfully!\n",sock_fd,port);

        listen(sock_fd,MAX_CLIENT);

        memset(&cli_addr,0,sizeof(cli_addr));
        while(1)
        {
                printf("Wating for client connect...\n");
                client_fd = accept(sock_fd,(struct sockaddr*)&cli_addr,&cliaddr_len);
                if( client_fd < 0 )
                {
                        printf("Accept client connect failure: %s\n",strerror(errno));
                        break;
                }
                printf("Accept client connect from [%s:%d]\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port) );

                memset(buf,0,sizeof(buf));
                rv = read( client_fd,buf,sizeof(buf) );
                if(rv < 0)
                {
                        printf("Read data from server by sockfd[%d] faliure: %s\n",client_fd,strerror(errno));
                        close(client_fd);
                        continue;
                }
                else if( 0 == rv )
                {
                        printf("Sockfd[%d] get disconnected\n",client_fd);
                        close(client_fd);
                        continue;
                }
                else if( rv > 0 )
                {
                        printf("Read %d bytes data from server: '%s'\n",rv,buf);
                }

                rv = write(client_fd,MSG_STR,strlen(MSG_STR));
                if( rv < 0 )
                {
                        printf("write to client by sockfd[%d] failure: %s\n",sock_fd,strerror(errno));
                        close(client_fd);
                        continue;
                }

                printf("Close client socket[%d]\n",client_fd);
                close(client_fd);
        }

        close(sock_fd);

        return 0;
}

socket域名解析

在我们写网络socket的客户端的时候,我们一般直接使用的是服务器端的IP地址,这相对来说具有一定的局限性,我们可以通过socket的域名解析函数来实现域名解析。

getaddrinfo()

int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
struct addrinfo {
    int              ai_flags;
    int              ai_family;
    int              ai_socktype;
    int              ai_protocol;
    socklen_t        ai_addrlen;
    struct sockaddr *ai_addr;
    char            *ai_canonname;
    struct addrinfo *ai_next;
};

getnameinfo()

int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);

gethostbyname()

用域名或主机名获取IP地址

struct hostent *gethostbyname(const char *name);

这个函数的传入值是域名或者主机名。返回值是一个hostent的结构体。如果函数调用失败,返回NULL。结构如下:

struct hostent
{
        char    *h_name;     //主机的规范名          
        char    **h_aliases;	//主机的别名
        int     h_addrtype;	//主机ip地址的类型,到底是ipv4(AF_INET),还是pv6(AF_INET6)
        int     h_length;	//主机ip地址的长度
        char    **h_addr_list;	/*主机的ip地址,注意,这个是以网络字节序存储的。不能直接用printf带%s参数来打这个东西。所以到真正需要打印出这个IP的话,需要调用inet_ntop()。*/
};

标签:serv,addr,int,APUE,通信,fd,printf,socket
From: https://www.cnblogs.com/LiBlog--/p/17964291

相关文章

  • NGINX 路由配置与参数详解(https配置、跨域配置、socket配置)
    目录一、概述二、https配置1)获取SSL证书2)安装SSL证书3)Nginx配置修改4)重新加载Nginx配置三、nginx跨域配置四、nginxsocket配置五、NGINX路由配置1)基本的URI匹配2)nginx中斜杠(/)1、location以斜杠结尾,proxy_pass不以斜杠结尾2、location不以斜杠结尾,proxy_pass......
  • socket
    引入Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。所以,我们无需深入理解tcp/udp协议,socket已经......
  • linux 内核和应用层之间的通信方式
    系统调用应用与内核通信的方式中,最常用的就是系统调用。如常见的open、write、read、ioctl等系统调用。当系统调用时,触发一个软中断,处理器进入内核模式。参数传递到内核空间,完成通信过程。内核完成服务之后,将数据返回给应用,并设置处理器为用户模式。copy_to_user()/copy_from_......
  • boost框架 创建websocket非阻塞服务
    #include<iostream>#include<boost/asio.hpp>#include<boost/beast.hpp>#include<boost/beast/websocket.hpp>namespaceasio=boost::asio;namespacebeast=boost::beast;namespacewebsocket=beast::websocket;usingtcp=asio::......
  • CAN通信配置过滤器和使用三个邮箱发送
    RM比赛用的电机基本都使用CAN通信,但是一条CAN线上只用一个发送邮箱在挂在设备多的情况可能会导致发送不完,但其实完全可以把三个发送邮箱都用上。这里贴一下自己的CAN筛选器,接收以及发送的代码。完整的工程可以看我开源的飞机云台程序~项目代码开源地址:https://github.com/ittuann......
  • 深入理解 Hadoop (一)网络通信架构与源码浅析
    HadoopRPC网络通信框架原理剖析YARNRPC服务端的工作大致可以分为四个阶段:第一个阶段:Server初始化和启动在Server初始化的时候,会初始化Listener组件(内部启动了一个AcceptSelector绑定了相应的端口,用来处理客户端的OP_ACCEPT事件),内部还初始化了一组Reader线程,其......
  • WebSocket-FLV H264/H265服务器基本实现
    场景HTTP-FLV:基于HTTP流式IO传输FLV,依赖浏览器支持播放FLV。但是由于同源的限制问题,浏览器只能播放六路视频,因此采用WebSocket-FLVWebSocket-FLV:基于WebSocket传输FLV,依赖浏览器支持播放FLV。WebSocket建立在HTTP之上,建立WebSocket连接前还要先建立HTTP连接。视频参数代码H264S......
  • 多种 React 组件通信方式实践
    使用ReactContext基于ReactContext实现跨组件通信的一个常见用例是创建一个能够在不同组件间共享和触发行为的上下文。以下是一个简化的例子,展示了如何在app.tsx中触发其他组件(例如,一个弹窗组件)中的方法。1.创建一个Context首先,我们创建一个新的Context。这个Context将......
  • python socket服务端
    pythonsocket服务端importsocket#创建socket对象server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#绑定IP地址和端口号server_socket.bind(('127.0.0.1',8000))#监听连接server_socket.listen(1)print('等待客户端连接...')whileTru......
  • UDP通信 [补档-2023-07-22]
    UDP通信6-1简介​UDP通信是面向无链接的,不稳定,不可靠,不安全的一种通信方式。TCP在通信前发送方会向接收方进行三次握手链接,然后确认双方链接后才会进行数据传输,最后四次挥手保证链接关闭。而UDP不会三次握手四次挥手,它会直接向发送方发送数据,无论接收方是否会收到,所以UDP更......