嵌入式学习——虚拟机通信

目录

虚拟机talk通信

自主编程实现通信(1)

自主编程实现通信(2)


虚拟机talk通信

如果我们想在虚拟机上与其他同学或朋友取得联系,我们可以使用talk程序进行交流。首先我们要打开虚拟机,执行以下命令,安装talk程序;

sudo apt update

sudo apt installbsd-talk

然后使用命令启动程序;

sudo systemctl start talk

sudo ufw allow talk

接着我们就可以使用命令进行通信;

talk fangjq

(这里talk 后面接上你想要通信的用户)

这里要注意输入内容以及一些快捷键,否则会出现一些问题;例如^Z是使用了CTRL快捷键,回复的Hello后面的问号是输入问题。

自主编程实现通信(1)

在同一终端下,子进程与父进程的通信;

首先创建一个目录:chat_program用来存放我们的相关文件

mkdir chat_program //创建目录

cd chat_program //进入目录

nano chat.c //创建文件

然后粘贴以下的代码,

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/select.h>

#define BUFFER_SIZE 1024

#define EXIT_CMD "exit"

int main() {

    int pipefd[2]; // 父进程到子进程的管道

    int pipefd2[2]; // 子进程到父进程的管道

    pid_t pid;

    // 创建两个管道

    if (pipe(pipefd) == -1 || pipe(pipefd2) == -1) {

        perror("pipe");

        exit(EXIT_FAILURE);

    }

    // 创建子进程

    pid = fork();

    if (pid == -1) {

        perror("fork");

        exit(EXIT_FAILURE);

    }

    if (pid == 0) {

        // 子进程:从父进程接收消息并通过另一个管道发送消息

        close(pipefd[1]); // 关闭写端

        close(pipefd2[0]); // 关闭读端

        char buffer[BUFFER_SIZE];

        fd_set readfds;

        int max_fd = (pipefd[0] > pipefd2[1]) ? pipefd[0] : pipefd2[1];

        while (1) {

            FD_ZERO(&readfds);

            FD_SET(STDIN_FILENO, &readfds);

            FD_SET(pipefd[0], &readfds);

            if (select(max_fd + 1, &readfds, NULL, NULL, NULL) == -1) {

                perror("select");

                exit(EXIT_FAILURE);

            }

            if (FD_ISSET(STDIN_FILENO, &readfds)) {

                // 从标准输入读取消息并发送给父进程

                ssize_t bytes_read = read(STDIN_FILENO, buffer, BUFFER_SIZE);

                if (bytes_read <= 0) {

                    break;

                }

                buffer[bytes_read - 1] = '\0'; // 去掉换行符

                if (strcmp(buffer, EXIT_CMD) == 0) {

                    write(pipefd2[1], buffer, strlen(buffer) + 1);

                    break;

                }

                write(pipefd2[1], buffer, strlen(buffer) + 1);

            }

            if (FD_ISSET(pipefd[0], &readfds)) {

                // 从父进程接收消息并输出

                ssize_t bytes_read = read(pipefd[0], buffer, BUFFER_SIZE);

                if (bytes_read <= 0) {

                    break;

                }

                buffer[bytes_read] = '\0';

                printf("Parent: %s\n", buffer);

                if (strcmp(buffer, EXIT_CMD) == 0) {

                    break;

                }

            }

        }

        close(pipefd[0]);

        close(pipefd2[1]);

        exit(EXIT_SUCCESS);

    } else {

        // 父进程:从子进程接收消息并通过另一个管道发送消息

        close(pipefd[0]); // 关闭读端

        close(pipefd2[1]); // 关闭写端

        char buffer[BUFFER_SIZE];

        fd_set readfds;

        int max_fd = (pipefd2[0] > pipefd[1]) ? pipefd2[0] : pipefd[1];

        while (1) {

            FD_ZERO(&readfds);

            FD_SET(STDIN_FILENO, &readfds);

            FD_SET(pipefd2[0], &readfds);

            if (select(max_fd + 1, &readfds, NULL, NULL, NULL) == -1) {

                perror("select");

                exit(EXIT_FAILURE);

            }

            if (FD_ISSET(STDIN_FILENO, &readfds)) {

                // 从标准输入读取消息并发送给子进程

                ssize_t bytes_read = read(STDIN_FILENO, buffer, BUFFER_SIZE);

                if (bytes_read <= 0) {

                    break;

                }

                buffer[bytes_read - 1] = '\0'; // 去掉换行符

                if (strcmp(buffer, EXIT_CMD) == 0) {

                    write(pipefd[1], buffer, strlen(buffer) + 1);

                    break;

                }

                write(pipefd[1], buffer, strlen(buffer) + 1);

            }

            if (FD_ISSET(pipefd2[0], &readfds)) {

                // 从子进程接收消息并输出

                ssize_t bytes_read = read(pipefd2[0], buffer, BUFFER_SIZE);

                if (bytes_read <= 0) {

                    break;

                }

                buffer[bytes_read] = '\0';

                printf("Child: %s\n", buffer);

                if (strcmp(buffer, EXIT_CMD) == 0) {

                    break;

                }

            }

        }

        close(pipefd[1]);

        close(pipefd2[0]);

        wait(NULL); // 等待子进程结束

    }

    return 0;

}

随后通过gcc编译器编译一遍,接着运行,尝试通信;

gcc chat.c -o chat

./chat

完成过后可以通过CTRL+C退出程序。在这段程序中,使用两个进程互相通信,首先根据用户输入的内容,子进程接收过后输出,发出第一段对话,然后用户再输入,接着父进程接收并输出,完成对子进程的回应,这段代码是子进程与父进程轮流对话,灵活性较低,不能多段输出,只能轮回。

除了这种,还有两个终端的对话。

自主编程实现通信(2)

在同一个账号两个终端之间通信;

这里建议先使用IPC或消息管道、消息槽等模式,然后进行实践。

使用以下命令创建管道文件,

mkfifo mypipe

在虚拟机中,管道文件(通常指命名管道或 FIFO 文件)是一种进程间通信(IPC)机制,用于在虚拟机内部或虚拟机与主机之间传递数据。通过创建命名管道文件(如 mkfifo 命令),虚拟机内部的进程可以实现通信。

首先创建两个文件,sender.c和receiver.c,然后输入以下代码;

nano sender.c

nano receive.c

sender.c:

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

 

int main() {

    int fd = open("mypipe", O_WRONLY);

    if (fd == -1) {

        perror("open");

        return 1;

    }

 

    char buffer[100];

    printf("Enter message: ");

    fgets(buffer, sizeof(buffer), stdin);

    write(fd, buffer, strlen(buffer)+1);

    close(fd);

    return 0;

}

receiver.c:

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

 

int main() {

    int fd = open("mypipe", O_RDONLY);

    if (fd == -1) {

        perror("open");

        return 1;

    }

 

    char buffer[100];

    read(fd, buffer, sizeof(buffer));

    printf("Received message: %s", buffer);

    close(fd);

    return 0;

}

同样的操作进行编译,编译过后终端一运行sender.c,终端二运行receive.c,测试运行结果。

可以看到,发送hello,也能接收到hello,这个程序的问题在于只能一条一条发送,而且单项发送。

CarpVM 是一个用 C 语言编写的小型虚拟机。可以嵌入在应用程序中使用。 包含的指令集有: HALT (code): Halts and attempts to clean up stack, data memory, and label memory before exiting with given exit code. NOP (): Does nothing. Seriously. LOAD (reg, val): Loads given integer value into given register. MOV (dst, src): Copies contents of src register into dst register. ADD (): Pops the top two integers from the stack and pushes their sum. SUB (): Pops the top two integers from the stack and pushes the difference (lower minus upper). MUL (): Pops the top two integers from the stack and pushes their product. MOD (rega, regb): Computes rega % regb and stores in ERX. NOT (reg): Computes bitwise NOT of reg and stores in reg. XOR (): Pops the top two integers from the stack and XORs them. OR (): Pops the top two integers from the stack and ORs them. AND (): Pops the top two integers from the stack and ANDs them. INCR (reg): Increments value in given register. DECR (reg): Decrements value in given register. INC (): Increments the value at the top of the stack. DEC (): Decrements the value at the top of the stack. PUSHR (reg): Pushes value in given register. PUSH (val): Pushes given value. POP (val): Pops an integer from the stack and dumps it into GBG. CMP (): Pops the top two integers from the stack and checks if equal. 0 means equal. Result will be pushed onto the stack. MOV (rega, regb): Move value in rega to regb. JZ (addr): Jumps to given absolute address if top of the stack is 0. RJZ (diff): Adds differential to current EIP (relative jump) if top of the stack is 0. JNZ (addr): Jumps to given absolute address if top of the stack is not 0. RJNZ (diff): Adds differential to current EIP (relative jump) if top of the stack is not 0. JMP (addr): Jumps to given absolute address. RJMP (diff): Adds differential to current EIP (relative jump). DBS (key, val): Sets data memory at key (string pointer) to given value. DBG (key, reg): Gets value from data memory at key (string pointer) and dumps it into given register. CALL (key, nargs): Save state and set EIP to value in data memory at key. RET (val): Push return value and load state. PREG (reg): Prints contents of given register. PTOP (): Peeks top of stack and prints top value. 标签:CarpVM
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值