【完美体育·(中国)手机网页版MYD-Y6ULX-V2开发板】socket通信和epoll
文章来源: 发布日期:2023.3.1 浏览次数:626 次 |
由评测者“华仔stm32”提供。
前面创建了socket 单线程的通信。如果客端连接断开后,主服务端也就断开。学习了博客园的@liangf27的帖子来实现单线程服务多个客户端。
修改main.c代码如下:
#include#include #include // open function #include // close function #include #include #include #include #include #include #include "ssd1306.h" const int PORT = 8888; /* listen_loop(): epoll监听套接字,作不同处理 accept_conn(): 新的客户端连接进来,执行accept,将fd加入epoll set recv_message(): recv并且重复输出一份给客户端 */ void listen_loop(); void accept_conn(unsigned int sock_fd, unsigned int epollfd); void recv_message(unsigned int sock_fd); int main(void) { int sock_fd; struct sockaddr_in server_addr; SSD1306_init(); SSD1306_clearDisplay(); SSD1306_setBrightness(255); SSD1306_setPageMode(); SSD1306_setTextXY(0,0); SSD1306_putString("HELLO MYD-Y6ULX!"); SSD1306_setTextXY(1,0); SSD1306_putString("SSD1306 DEMO"); SSD1306_setTextXY(2,0); SSD1306_putString("2022-11-07"); //初始化socket sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (sock_fd < 0) { perror("socket:"); return 0; } //编辑地址 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET;//ipv_4 server_addr.sin_port = htons(PORT);//监听端口8888 server_addr.sin_addr.s_addr = INADDR_ANY;//本地的任意地址 //绑定然后监听 if (bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("bind:"); return 0; } if (listen(sock_fd, 10) < 0) { perror("listen"); return 0; } listen_loop(sock_fd); return 0; } void accept_conn(unsigned int sock_fd, unsigned int epollfd) { struct sockaddr_in clientaddr; struct epoll_event event; socklen_t len = sizeof(struct sockaddr); int accept_fd = 0; accept_fd = accept(sock_fd, (struct sockaddr*)&clientaddr, &len); if (accept_fd <= 0) { perror("accept error"); return; } //将新建连接加入epoll set event.data.fd = accept_fd; event.events = EPOLLIN | EPOLLET | EPOLLRDHUP; epoll_ctl(epollfd, EPOLL_CTL_ADD, accept_fd, &event); return; } void recv_message(unsigned int sock_fd) { char recv_buf[1024], send_buf[1024]; memset(recv_buf, 0, sizeof(recv_buf)); memset(send_buf, 0, sizeof(send_buf)); recv(sock_fd, recv_buf, sizeof(recv_buf), 0); //接收到数据后,在这里写处理逻辑,我这里把接收到的数据显示到OLED屏上,并原样的回发给客户端。 fputs(recv_buf, stdout); strcpy(send_buf, recv_buf); SSD1306_clearDisplay(); SSD1306_setTextXY(3,0); SSD1306_putString(send_buf); send(sock_fd, send_buf, sizeof(send_buf), 0); return; } void listen_loop(unsigned int sock_fd) { int epollfd, i, ret; int timeout = 300; struct epoll_event event; struct epoll_event eventList[10]; /*创建epoll监听事件*/ epollfd = epoll_create(10); event.events = EPOLLIN | EPOLLET; event.data.fd = sock_fd; /*注册epoll监听事件.*/ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sock_fd, &event) < 0) { printf("register epoll event err !"); return; } while (1) { ret = epoll_wait(epollfd, eventList, 10, timeout); /*epoll事件错误.*/ if (ret < 0) { printf("epoll event err!"); break; } /*无事件返回.*/ else if (ret == 0) { continue; } /*epoll返回事件.*/ for (i = 0; i < ret; i++) { /*epoll 错误*/ if ((eventList[i].events & EPOLLERR) || (eventList[i].events & EPOLLHUP) || !(eventList[i].events & EPOLLIN)) { printf("epoll error\n"); close(eventList[i].data.fd); exit(-1); } //half connection if (eventList[i].events & EPOLLRDHUP) { printf("//one client close the conne.//\n"); close(eventList[i].data.fd); } /*accept事件*/ if (eventList[i].data.fd == sock_fd) { accept_conn(sock_fd, epollfd); } /*非sock_fd则为其他事件.*/ else { recv_message(eventList[i].data.fd); } } } close(epollfd); close(sock_fd); return; }