内存共享实现聊天室程序

     聊天室程序中至少要求每个用户的发言能立即呈现给其它用户,为了提高效率,每个用户连接在服务端都对应一个子进程处理该用户连接。所有用户的发言数据记录在一个用户共享内存中,假设A用户发言了那么共享内存中某段数据t对应A的发言数据,用户B对应的子进程是pid_b处理用户B,那么pid_b只要到到共享内存位置t读取A的发言数据并发送给B,则聊天室逻辑就成立了。为了达到该设计需求,服务端主进程监听端口遇见有用户连接请求就fork一个子进程处理该用户连接。子进程收到其对应的用户发言数据了就通过管道告诉主进程我(这个子进程)有话要说,此时主进程将这些话传送给其它子进程要求这些子进程将这些话发送给它们对用的客户。而这些发言数据通过共享内存实现只需要传递些指针即可,且每个子进程只需要向其对应的位置写数据所以不会出现交叉写的竞态。

服务端程序:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

#define USER_LIMIT 5//最大客户数
#define BUFFER_SIZE 1024//缓冲区
#define FD_LIMIT 65535//最大支持文件数目
#define MAX_EVENT_NUMBER 1024//最大事件数
#define PROCESS_LIMIT 65536//最大子进程数

struct client_data//客户数据
{
    sockaddr_in address;//客户端地址
    int connfd;//客户连接描述符
    pid_t pid;//处理该连接的子进程号
    int pipefd[2];//管道描述符用户主进程向子进程之间传递数据是socketpair全双工管道,pipefd[0]用于主进程向子进程写入数据,pipefd[1]用于子进程监听主进程是否有数据发送到来
};

static const char* shm_name = "/my_shm";
int sig_pipefd[2];//传递信号值的管道(用于将信号事件与IO事件统一监听)
int epollfd;//事件表描述符
int listenfd;//服务端监听端口
int shmfd;//共享内存标示符
char* share_mem = 0;//共享内存地址
client_data* users = 0;//客户数据数组
int* sub_process = 0;//每个子进程pid对应处理的那个客户编号,采用pid作为数组索引下标得到客户编号
int user_count = 0;//当前连接用户
bool stop_child = false;//终止子进程

int setnonblocking( int fd )//将文件描述符设置为非阻塞
{
    int old_option = fcntl( fd, F_GETFL );
    int new_option = old_option | O_NONBLOCK;
    fcntl( fd, F_SETFL, new_option );
    return old_option;
}

void addfd( int epollfd, int fd )//向注册表添加新的可读事件
{
    epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLET;
    epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event );
    setnonblocking( fd );
}

void sig_handler( int sig )//信号处理函数
{
    int save_errno = errno;
    int msg = sig;
    send( sig_pipefd[1], ( char* )&msg, 1, 0 );//通过管道sig_pipefd向主进程发送信号值
    errno = save_errno;
}

void addsig( int sig, void(*handler)(int), bool restart = true )//安装信号
{
    struct sigaction sa;
    memset( &sa, '\0', sizeof( sa ) );
    sa.sa_handler = handler;
    if( restart )
    {
        sa.sa_flags |= SA_RESTART;//是否重启由于信号中断的系统调用
    }
    sigfillset( &sa.sa_mask );
    assert( sigaction( sig, &sa, NULL ) != -1 );
}

void del_resource()//清理资源
{
    close( sig_pipefd[0] );
    close( sig_pipefd[1] );
    close( listenfd );
    close( epollfd );
    shm_unlink( shm_name );
    delete [] users;
    delete [] sub_process;
}

void child_term_handler( int sig )//设置终止子进程标志
{
    stop_child = true;
}

int run_child( int idx, client_data* users, char* share_mem
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 以下是使用C语言实现的两个程序,可以实现基于内存的交互式聊天程序1:客户端 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #define BUF_SIZE 256 int main(int argc, char *argv[]) { if (argc != 3) { printf("Usage: %s <Server IP> <Port>\n", argv[0]); exit(1); } char *server_ip = argv[1]; int server_port = atoi(argv[2]); // create socket int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); exit(1); } // connect to server struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(server_ip); server_addr.sin_port = htons(server_port); if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("connect"); exit(1); } // send and receive messages char buf[BUF_SIZE]; while (1) { printf("Enter message: "); fgets(buf, BUF_SIZE, stdin); if (send(sock, buf, strlen(buf), 0) < 0) { perror("send"); exit(1); } if (recv(sock, buf, BUF_SIZE, 0) < 0) { perror("recv"); exit(1); } printf("Received message: %s\n", buf); } // close socket close(sock); return 0; } ``` 程序2:服务器端 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #define BUF_SIZE 256 int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage: %s <Port>\n", argv[0]); exit(1); } int server_port = atoi(argv[1]); // create socket int server_sock = socket(AF_INET, SOCK_STREAM, 0); if (server_sock < 0) { perror("socket"); exit(1); } // bind socket to port struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(server_port); if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind"); exit(1); } // listen for incoming connections if (listen(server_sock, 1) < 0) { perror("listen"); exit(1); } // accept connections and send/receive messages int client_sock; struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); char buf[BUF_SIZE]; while (1) { printf("Waiting for client...\n"); client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_len); if (client_sock < 0) { perror("accept"); continue; ### 回答2: 使用C语言实现两个程序之间的交互式聊天可以通过共享内存进行通信。以下是实现的步骤: 1. 创建共享内存区域:使用shmget函数创建一个共享内存区域,并获得共享内存的标识符。 2. 连接共享内存:使用shmat函数将共享内存附加到进程的地址空间中,获得共享内存区域的指针。 3. 进程间通信:通过共享内存区域的指针,两个程序可以相互读写数据。可以使用信号量或其他同步机制确保数据的同步访问。 4. 聊天功能实现程序A可以通过向共享内存写入聊天消息,程序B则从共享内存读取聊天消息。反之,程序B也可以向共享内存写入消息,程序A则从共享内存读取消息。 5. 退出聊天:当聊天结束时,可以使用shmdt函数将共享内存从进程的地址空间中分离。 6. 删除共享内存:最后,使用shmctl函数删除共享内存区域,释放资源。 总结:使用C语言实现两个程序之间共享内存的交互式聊天主要涉及到创建、连接和释放共享内存,以及通过共享内存进行读写数据的操作。使用这种方式可以实现进程间的通信,从而实现聊天功能。 ### 回答3: 实现两个程序的互动式聊天,可以通过共享内存实现进程间的通信。下面是一个使用C语言实现的简单示例。 首先,需要创建一个共享内存区域。可以使用 `shmget()` 函数创建一个新的共享内存区域或者获取一个已存在的共享内存区域。 ```c int shmid = shmget(IPC_PRIVATE, sizeof(char) * BUFFER_SIZE, IPC_CREAT | 0666); ``` 接下来,通过调用 `shmat()` 函数将共享内存区域连接到进程的地址空间: ```c char* shared_memory = (char*) shmat(shmid, NULL, 0); ``` 现在,两个程序都可以通过读写共享内存来进行交互。例如,程序A可以将用户的输入写入到共享内存中: ```c strcpy(shared_memory, "Hello from Program A"); ``` 程序B可以读取共享内存中的数据并输出: ```c printf("Message from Program A: %s\n", shared_memory); ``` 为了使两个程序能够实现双向通信,可以使用信号量来同步进程间的操作。例如,程序A可以在写入共享内存之前先等待一个信号量,表示程序B已经读取完共享内存中的数据: ```c wait(semaphore); // 等待信号量 strcpy(shared_memory, "Hello from Program A"); signal(semaphore); // 发送信号量 ``` 程序B可以在读取完共享内存中的数据后发送一个信号量,告知程序A可以写入新的数据: ```c printf("Message from Program A: %s\n", shared_memory); signal(semaphore); // 发送信号量 ``` 这样,两个程序就可以通过共享内存和信号量来实现基本的交互式聊天功能。 请注意,这只是一个简单的示例,实际的实现可能需要更多的额外处理来处理并发访问。例如,使用互斥锁保护共享内存的写操作,以防止多个程序同时写入导致数据混乱。此外,还需要考虑异常情况下的处理,比如程序退出时要正确地释放共享内存和信号量等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值