Linux网络开发基础知识

news2024/11/26 0:50:15

一个网络服务器的简单实现

项目需求

实现回声服务器的客户端/服务器程序,客户端通过网络连接到服务器,并发送任意一串英文信息,服务器端接收信息后,

将每个字符转换为大写并回送给客户端显示。

eoch_client.c

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

#define SERVER_PORT 8080
#define SERVER_IP "127.0.0.1"

int main(int argc,char *argv[]) {
    if(argc != 2){
        fputs("Usage: ./echo_client message \n", stderr);
        exit(1);
    }

    int sockfd;
    struct sockaddr_in server_addr;
    memset(&server_addr, '\0', sizeof(server_addr));
    char buffer[1024];
    char * message = argv[1];
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);
    if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        printf("Connection failed\n");
    }
    write(sockfd, message, strlen(message));
    
    int len = read(sockfd, buffer, sizeof(buffer)-1);
     if(len>0){
        buffer[len]='\0';
        printf("receive: %s\n", buffer);
    }else {
        perror("error!!!");
    }
    printf("finished.\n");
    close(sockfd);

    return 0;
}

eoch_server.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>

#define PORT 8080
#define IP_ADDRESS "127.0.0.1"
#define BUFFER_SIZE 1024

int main(int argc, char *argv[]) {
    int sockfd;
    struct sockaddr_in server_addr;
    bzero((char * )&server_addr, sizeof(server_addr));
     
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
    
    bind(sockfd, (struct sockaddr * )&server_addr, sizeof(server_addr));
    listen(sockfd, 128);
    printf("Server is waiting for new connections on port %d...\n", PORT);
    
    int done = 1;
    while(done) {
        char * buffer = (char * )calloc(buffer, BUFFER_SIZE);
        struct sockaddr_in client_addr;
        int client_sockfd;
        int client_addr_len = sizeof(client_addr);
        accept(client_sockfd, (struct sockaddr * )&client_addr, &client_addr_len);
        printf("New connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        int len = read(client_sockfd, buffer, sizeof(buffer));
        buffer[BUFFER_SIZE] = '\0';
        printf("Received message from client[ip_address: %s, port: %d]: %s\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);
        for(int i = 0; i < len; i++) {
            /*
            if(buffer[i] >= 'a' && buffer[i] <= 'z')
                buffer[i] = buffer[i] - 32;//ASCII
            
            */
            buffer[i] = toupper(buffer[i]);//将小写转化为大写的函数
        }
        len = write(client_sockfd, buffer, sizeof(buffer));
        printf("Sent message to client[ip_address: %s, port: %d]: %s\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);
        close(client_sockfd);



    }
    close(sockfd);
    return 0;
    
}

网络通信和socket

socket通信三要素

  1. 通信的目的地址

  2. 使用的端口号(http 80,https 443,smtp 25

  3. 使用的传输协议层(TCP,UDP.etc,

socket通信模型

socket套接字详解

套接字的概念

Socket中文意思是“插座”,在Linux环境下,用于表示进程x间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。

既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是文件主要应用于本地持久化数据的读写,而套接字多应用于网络进程间数据的传递。

在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。

套接字通信原理如下图所示:

                                套接字通讯原理示意

在网络通信中,套接字一定是成对出现的。一端的发送缓冲区对应对端的接收缓冲区。我们使用同一个文件描述符索发送缓冲区和接收缓冲区。

Sockert通信流程图

网络字节序

在计算机世界里,有两种字节序:

大端字节序 - 低地址高字节,高地址低字节

小段字节序 - 低地址低字节,高地址高字节

\

内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分。网络数据流同样有大端小端之分,那么如何定义网络数据流的地址呢?发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。

例如端口号是1001(0x3e9),由两个字节保存,采用大端字节序,则低地址是0x03,高地址是0xe9,也就是先发0x03,再发0xe9,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址存0xe9。但是,如果发送主机是小端字节序的,这16位被解释成0xe903,而不是1001。因此,发送主机把1001填到发送缓冲区之前需要做字节序的转换。同样地,接收主机如果是小端字节序的,接到16位的源端口号也要做字节序的转换。如果主机是大端字节序的,发送和接收都不需要做转换。同理,32位的IP地址也要考虑网络字节序和主机字节序的问题。

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

#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位短整数。

如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

sockaddr数据结构

很多网络编程函数诞生早于IPv4协议,那时候都使用的是sockaddr结构体,为了向前兼容,现在sockaddr退化成了(void *)的作用,传递一个地址给函数,至于这个函数是sockaddr_in还是其他的,由地址族确定,然后函数内部再强制类型转化为所需的地址类型。

struct sockaddr {
	sa_family_t sa_family; 		/* address family, AF_xxx */
	char sa_data[14];			/* 14 bytes of protocol address */
};

 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 */
};

IPv4的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位端口号和32位IP地址,但是sock API的实现早于ANSI C标准化,那时还没有void *类型,因此这些像bind 、accept函数的参数都用struct sockaddr *类型表示,在传递参数之前要强制类型转换一下,例如:

struct sockaddr_in servaddr;
bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));		
/* initialize servaddr */

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

af 取值可选为 AF_INET 和 AF_INET6 ,即和 ipv4 和ipv6对应 支持IPv4和IPv6

因此函数接口是void *addrptr。

demo

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>



int main(void){

    char ip[]="2.3.4.5";
    char server_ip[64];

    struct sockaddr_in server_addr;


    inet_pton(AF_INET, ip, &server_addr.sin_addr.s_addr);

    printf("s_addr : %x\n", server_addr.sin_addr.s_addr);

    printf("s_addr from net to host: %x\n", ntohl(server_addr.sin_addr.s_addr));

    inet_ntop(AF_INET, &server_addr.sin_addr.s_addr, server_ip, 64);

    printf("server ip : %s\n", server_ip);

    printf("INADDR_ANY: %d\n", INADDR_ANY);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    inet_ntop(AF_INET, &server_addr.sin_addr.s_addr, server_ip, 64);
    printf("INADDR_ANY ip : %s\n", server_ip);
    return 0;
}

Socket函数

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

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

domain:

AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址

AF_INET6 与上面类似,不过是来用IPv6的地址

AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用

type:

SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。

SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。

SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。

SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)

SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序

protocol:

传0 表示使用默认协议。

返回值:

成功:返回指向新创建的socket的文件描述符,失败:返回-1,设置errno

socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。对于IPv4,domain参数指定为AF_INET。对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表示面向数据报的传输协议。protocol参数的介绍从略,指定为0即可。

blind函数

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

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

sockfd:

socket文件描述符

addr:

构造出IP地址加端口号

addrlen:

sizeof(addr)长度

返回值:

成功返回0,失败返回-1, 设置errno

服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接,因此服务器需要调用bind绑定一个固定的网络地址和端口号。

bind()的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。前面讲过,struct sockaddr *是一个通用指针类型,addr参数实际上可以接受多种协议的sockaddr结构体,而它们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度。如:

 
struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);

首先将整个结构体清零,然后设置地址类型为AF_INET,网络地址为INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP地址,这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址,端口号为6666。

listen函数

#include <sys/types.h> /* See NOTES */
​
#include <sys/socket.h>
​
int listen(int sockfd, int backlog);
​

sockfd:

socket文件描述符

backlog:

在Linux 系统中,它是指排队等待建立3次握手队列长度

查看系统默认backlog

cat /proc/sys/net/ipv4/tcp_max_syn_backlog

改变 系统限制的backlog 大小

vim /etc/sysctl.conf

最后添加 net.core.somaxconn = 1024

net.ipv4.tcp_max_syn_backlog = 1024

保存,然后执行 sysctl -p

典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更多的连接请求就忽略。listen()成功返回0,失败返回-1。

accpet函数

#include <sys/types.h>      /* See NOTES */
#include <sys/socket.h>
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockdf:

socket文件描述符

addr:

传出参数,返回链接客户端地址信息,含IP地址和端口号

addrlen:

传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小

返回值:

成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errn

三次握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。addr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。如果给addr参数传NULL,表示不关心客户端的地址。

我们的服务器程序结构是这样的:

while (1) {
    cliaddr_len = sizeof(cliaddr);
    connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
    n = read(connfd, buf, MAXLINE);
    ......
    close(connfd);
}

整个是一个while死循环,每次循环处理一个客户端连接。由于cliaddr_len是传入传出参数,每次调用accept()之前应该重新赋初值。accept()的参数listenfd是先前的监听文件描述符,而accept()的返回值是另外一个文件描述符connfd,之后与客户端之间就通过这个connfd通讯,最后关闭connfd断开连接,而不关闭listenfd,再次回到循环开头listenfd仍然用作accept的参数。accept()成功返回一个文件描述符,出错返回-1。

connect函数

#include <sys/types.h>                  /* See NOTES */
#include <sys/socket.h>
    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockdf:

socket文件描述符

addr:

传入参数,指定服务器端地址信息,含IP地址和端口号

addrlen:

传入参数,传入sizeof(addr)大小

返回值:

成功返回0,失败返回-1,设置errno

客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。connect()成功返回0,出错返回-1。

出错处理函数

我们知道,系统函数调用不能保证每次都成功,必须进行出错处理,这样一方面可以保证程序逻辑正常,另一方面可以迅速得到故障信息。

出错处理函数

#include <errno.h>
​
#include <string.h>
​
char *strerror(int errnum);   /* See NOTES */

errnum:

传入参数,错误编号的值,一般取 errno 的值

返回值:

错误原因

#include <stdio.h>
​
#include <errno.h>
​
void perror(const char *s);   /* See NOTES */

s

传入参数,自定义的描述

返回值:

向标准出错stderr 输出出错原因

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

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

相关文章

Android双向认证配置过程

1&#xff08;可以绕过&#xff09;准备过程 为了让这个教程可以一直复用&#xff0c;打算直接写一个双向认证的APP作为素材。 工具&#xff1a; ●protecle&#xff08;签名文件转换&#xff09; ●keytool&#xff08;java自己就有&#xff09; ●openssl&#xff08;apache里…

前端canvas项目实战——在线图文编辑器(九):逻辑画布

目录 前言一、 效果展示二、 实现步骤1. 调整布局&#xff0c;最大化利用屏幕空间2. 添加逻辑画布3. 添加遮罩4. 居中显示逻辑画布5. 一个容易被忽视的bug点 三、Show u the code后记 前言 上一篇博文中&#xff0c;我们实现了一组通用的功能按钮&#xff1a;复制、删除、锁定…

LeetCode-hot100题解—Day5

原题链接&#xff1a;力扣热题-HOT100 我把刷题的顺序调整了一下&#xff0c;所以可以根据题号进行参考&#xff0c;题号和力扣上时对应的&#xff0c;那么接下来就开始刷题之旅吧~ 1-8题见LeetCode-hot100题解—Day1 9-16题见LeetCode-hot100题解—Day2 17-24题见LeetCode-hot…

httpClient提交报文中文乱码

httpClient提交中文乱码&#xff0c;ContentType类型application/json 指定提交参数的编码即可 StringEntity se new StringEntity(paramBody.toJSONString(),"UTF-8");se.setContentType("application/json");context.httpPost.setHeader("Cookie&…

Go-Zero从0到1实现微服务项目开发(二)

前言 书接上回&#xff0c;继续更新GoZero微服务实战系列文章。 上一篇被GoZero作者万总点赞了&#xff0c;更文动力倍增&#xff0c;也建议大家先看巧一篇&#xff0c;欢迎粉丝股东们三连支持一波&#xff1a;Go-zero微服务快速入门和最佳实践&#xff08;一&#xff09; 本…

Windows Server 2022 OVF, updated Apr 2024 (sysin) - VMware 虚拟机模板

Windows Server 2022 OVF, updated Apr 2024 (sysin) - VMware 虚拟机模板 2024 年 4 月版本更新&#xff0c;现在自动运行 sysprep&#xff0c;支持 ESXi Host Client 部署 请访问原文链接&#xff1a;Windows Server 2022 OVF, updated Apr 2024 (sysin) - VMware 虚拟机模…

从Kernel启动到Android系统整个过程源码分析

1、 第一阶段&#xff1a; 对于ARM的处理器&#xff0c;内核第一个启动的文件是arc/arm/kernel下面的head.S文件。当然arc/arm/boot/compress下面也有这个文件&#xff0c;这个文件和上面的文件略有不同&#xff0c;当要生成压缩的内核时zImage时&#xff0c;启动的是后者&…

企业如何保证内部传输文件使用的工具是安全的?

企业内部文件的频繁交换成为了日常运营不可或缺的一环。然而&#xff0c;随着数据量的爆炸式增长和网络攻击手段的日益复杂&#xff0c;内网文件传输的安全隐患也日益凸显&#xff0c;成为企业信息安全的薄弱环节。本文将探讨内网文件传输的安全风险、企业常用的防护措施。 内网…

《Fundamentals of Power Electronics》——Buck、Boost、Buck-Boost三个电路的CCM-DCM工作特性总结

Buck、Boost、Buck-Boost这三个电路的CCM-DCM工作特性总结如下表所示&#xff1a; Buck、Boost、Buck-Boost这三个电路工作在DCM模式下电压传输比的对比图如下所示&#xff1a; 由上图可知&#xff0c;Buck-Boost电路的工作特性是一条斜率为的直线&#xff0c;Buck电路和Boost电…

小长假来临,企业借助巡检系统做好安全巡查工作

节前节后是安全隐患事故多发期&#xff0c;小长假来了&#xff0c;企业面临着员工离岗、生产活动减少等特殊情况&#xff0c;这可能导致一些安全隐患被忽视。因此&#xff0c;借助巡检系统做好全面安全巡查工作显得尤为重要。巡检系统可以帮助企业实现巡检工作的规范化、标准化…

八_实验1:创建 VLAN 和划分端口

1、实验目的 通过本实验可以掌握&#xff1a; VLAN的概念。创建VLAN的方法。把交换机端口划分到VLAN中的方法。 2、实验​​​​​​拓扑 创建 VLAN 和划分端口的实验拓扑如下图所示。 图8-5 创建 VLAN 和划分端口的实验拓扑 3、实验步骤 &#xff08;1&#xff09;实验准…

C++:map和set的封装

关于红黑树的模拟实现&#xff0c;大家不清楚的先去看看博主的博客再来看这篇文章&#xff0c;因为set和map的封装底层都是利用用的红黑树。所以这里不会过多介绍红黑树的相关内容&#xff0c;而更多的是去为了契合STL中的红黑树去进行改造&#xff0c;让封装的set和map能够去复…

第二篇:Python环境搭建:从初学者到专家

Python环境搭建&#xff1a;从初学者到专家 在编程的世界里&#xff0c;准备好一个高效而舒适的开发环境是走向成功的第一步。在这篇博客文章中&#xff0c;我们将一起探索如何为Python编程搭建一个理想的环境。无论你是完全的新手还是希望提升现有的技能&#xff0c;本文都会…

常用图像加密技术-流密码异或加密

异或加密是最常用的一种加密方式&#xff0c;广泛的适用于图像处理领域。这种加密方式依据加密密钥生成伪随机序列与图像的像素值进行异或操作&#xff0c;使得原像素值发生变化&#xff0c;进而使得图像内容发生变化&#xff0c;达到保护图像内容的目的。 该加密方法是以图像…

C语言程序设计(一)

1、指令、程序、软件 2、计算机语言&#xff1a;机器语言、汇编语言、高级语言 高级语言的发展&#xff1a;非结构化语言&#xff08;FORTRAN&#xff09;、结构化语言&#xff08;C语言&#xff09;、面向对象的语言&#xff08;C、面向对象&#xff09; 3、源程序、二进制…

在ubuntu 24.04 上安装vmware workstation 17.5.1

ubuntu安装在新组装的i9 14900机器上&#xff0c;用来学习笨叔的ARM64体系结构编程&#xff0c;也熟悉Linux的用法。但有时候写文档总是不方便&#xff0c;还是需要window来用。因此想在ubuntu 24.04上安装Linux版本的vmware worksation 17.5.1以虚拟机的方式安装windows 11。其…

Kubernetes学习笔记03

第八章、Kubernetes控制器Controller详解 Statefulset Statefulset主要是用来部署有状态应用 对于StatefulSet中的Pod&#xff0c;每个Pod挂载自己独立的存储&#xff0c;如果一个Pod出现故障&#xff0c;从其他节点启动一个同样名字的Pod&#xff0c;要挂载上原来Pod的存储…

Vitis HLS 学习笔记--AXI4 主接口

目录 1. 简介 2. 认识MAXI 3. MAXI突发操作 3.1 全局/本地存储器 3.2 MAXI优势与特点 3.3 查看MAXI报告 3.3.1 HW Interfaces 3.3.2 M_AXI Burst Information 3.4 MAXI 资源消耗 4. 理解 Volatile 4.1 标准C/C中的 volatile 4.2 HLS 中的 volatile 5. 总结 1. 简介…

CACTER AI实验室:AI大模型在邮件安全领域的应用

随着人工智能技术的飞速发展&#xff0c;AI已经深入到生活的各个领域。AI大模型在邮件安全领域展现出巨大潜力&#xff0c;尤其是反钓鱼检测上的应用&#xff0c;正逐渐展现出其独特的价值。 4月24日&#xff0c;CACTER AI实验室高级产品经理刘佳雄在直播交流会上分享了CACTER …

飞腾FT2000/4+银河麒麟全国产VPX架构 6U尺寸标准板卡,适用于船舶、交通等领域

XM-FT2000-VPX主板 XM-FT2000-VPX主板为VPX架构 6U尺寸标准板卡&#xff0c;提供的接口有DVI、USB、网络、UART、PCIE等接口。 处理器&#xff1a; FT2000/4四核国产处理器 芯片&#xff1a; 兆芯ZX-200芯片组 内存&#xff1a; 国产内存颗粒&#xff0c;双通道DDR4&#xff0…