ZBLOG

、epoll模型下,一个socket同时recv send,C语言客户端示例

epoll 模型下,实现一个能够同时处理 recvsend 的 C 语言客户端示例,可以使用多线程或非阻塞 I/O。下面是一个简单的非阻塞 I/O 示例,它展示了如何使用 epoll 来处理 socket 的读写事件。

客户端代码示例

这个示例创建了一个 TCP 客户端,连接到服务器,并能够同时接收和发送数据。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/epoll.h>

#define SERVER_PORT 8080
#define SERVER_IP "127.0.0.1"
#define MAX_EVENTS 10
#define BUFFER_SIZE 1024

// 设置socket为非阻塞模式
int set_nonblocking(int sock) {
    int flags = fcntl(sock, F_GETFL, 0);
    if (flags == -1) return -1;
    return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}

int main() {
    int sock;
    struct sockaddr_in server_addr;

    // 创建 socket
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // 设置为非阻塞模式
    if (set_nonblocking(sock) == -1) {
        perror("set_nonblocking");
        close(sock);
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址结构体
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);

    // 将 IP 地址转换为二进制形式
    if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) {
        perror("Invalid address / Address not supported");
        close(sock);
        exit(EXIT_FAILURE);
    }

    // 尝试连接到服务器
    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        if (errno != EINPROGRESS) {
            perror("Connection failed");
            close(sock);
            exit(EXIT_FAILURE);
        }
        
        printf("Connecting to the server...\n");
        
        // 使用 epoll 等待连接完成
        struct epoll_event event;
        struct epoll_event events[MAX_EVENTS];
        
        int epfd = epoll_create1(0);
        if (epfd == -1) {
            perror("epoll_create1");
            close(sock);
            exit(EXIT_FAILURE);
        }

        event.events = EPOLLOUT; // 我们关注可写事件
        event.data.fd = sock;
        
        if (epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &event) == -1) {
            perror("epoll_ctl: listen_sock");
            close(epfd);
            close(sock);
            exit(EXIT_FAILURE);
        }
        
        while (1) {
            int n = epoll_wait(epfd, events, MAX_EVENTS, -1); // 等待事件发生
            
            for (int i = 0; i < n; i++) {
                if (events[i].data.fd == sock && events[i].events & EPOLLOUT) {
                    printf("Connected to the server\n");

                    // 一旦连接成功,可以移除EPOLLOUT并添加EPOLLIN事件来监听输入数据
                    event.events = EPOLLIN | EPOLLET; 
                    epoll_ctl(epfd, EPOLL_CTL_MOD, sock, &event);

                    break;
                }
            }
            
            break; // 成功连接后退出循环
         } 
        
         close(epfd); 
     }

     char buffer[BUFFER_SIZE];

     while(1){
         printf("Enter message: ");
         fgets(buffer, BUFFER_SIZE-2 , stdin); 
         
         size_t len = strlen(buffer); 
         buffer[len] = '\n'; 
         buffer[len + 1] = '\0'; 

         send(sock , buffer , strlen(buffer), MSG_NOSIGNAL); 

         event.events = EPOLLIN | EPOLLET;
         event.data.fd = sock;

         int epfd2 = epoll_create1(0); 
         
          if(epfd2==-1){ 
             perror ("epoll_create"); 
             break ;  
          } 

          epoll_ctl(epfd2 ,EPOLL_CTL_ADD,sock,&event);

          while(1){ 
              int n=epoll_wait(epfd2 ,events ,MAX_EVENTS,-1 ); 

              for(int i=0;i<n;i++){ 
                  if(events[i].data.fd==sock && events[i].events&EPOLLIN){  
                      ssize_t recv_bytes=recv(sock ,buffer,sizeof(buffer)-1 ,MSG_NOSIGNAL );   

                      if(recv_bytes<=0){ 
                          perror ("recv failed or connection closed");  
                          break ;   
                      } 

                      buffer[recv_bytes]='\0';  
                      printf ("Server response: %s\n",buffer);  
                   }   
               }    
           }   
       }
      
      close(socket);   
      return EXIT_SUCCESS;  
}

使用说明:

编译程序

确保你的系统安装了 GCC 编译器,然后使用以下命令编译客户端代码:

gcc client.c -o client

运行服务器

首先,确保你已经运行了相应的服务端程序(例如前面提供的基于 epoll 的服务端)。

启动客户端

在另一个终端窗口中,运行客户端程序:

./client

用户交互

在客户端中,你可以输入消息并按回车键发送。之后,程序会等待来自服务器的响应并显示。

注意事项:

  • 确保你正确设置了 IP 地址和端口,以匹配你的服务器。
  • 此示例使用了边缘触发(Edge Triggered)模式,你可能需要根据具体需求调整。
  • 本代码主要用于学习目的,请根据生产环境需求进行适当修改和错误处理。


    内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:http://sdn.0voice.com/?id=7789

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?