forked from gary/ems
2
0
Fork 0
sun_ems/ems_c/driver/drv_tcp_server.c

288 lines
7.9 KiB
C
Raw Permalink Normal View History

2025-05-13 17:49:49 +08:00
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include "drv_tcp_server.h" // 包含您提供的头文件
#define MAX_TCP_LEN 1024 // 假设MAX_TCP_LEN定义为1024
#define MAX_EVENTS 10 // epoll等待的最大事件数
#define MAX_CLIENTS 10 // 最多客户端数
/*****************************************************************************
* @brief
* @param[in] fd:
* @return 0- 1-
*****************************************************************************/
static int setNonblocking(int fd)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1)
{
perror("fcntl F_GETFL failed");
return 1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
{
perror("fcntl F_SETFL failed");
return 1;
}
return 0;
}
/*****************************************************************************
* @brief tcp驱动
* @param[in] p_tcp:
* @return 0- 1-
*****************************************************************************/
int drvTcpServerOpen(tcp_server_lib_t* p_tcp)
{
if (p_tcp == NULL)
{
return 1;
}
// 创建socket
p_tcp->socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (p_tcp->socket_fd < 0)
{
perror("socket creation failed");
return 1;
}
// 设置SO_REUSEADDR以快速重用端口
int opt = 1;
if (setsockopt(p_tcp->socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
{
perror("setsockopt failed");
close(p_tcp->socket_fd);
return 1;
}
// 设置IP和端口
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(p_tcp->port);
if (inet_pton(AF_INET, p_tcp->ip, &server_addr.sin_addr) <= 0)
{
perror("Invalid IP address");
close(p_tcp->socket_fd);
return 1;
}
// 绑定socket到IP和端口
if (bind(p_tcp->socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
{
perror("Bind failed");
close(p_tcp->socket_fd);
return 1;
}
// 开始监听
if (listen(p_tcp->socket_fd, MAX_CLIENTS) < 0)
{
perror("Listen failed");
close(p_tcp->socket_fd);
return 1;
}
// 设置非阻塞模式
if (setNonblocking(p_tcp->socket_fd) > 0)
{
close(p_tcp->socket_fd);
return 1;
}
// 创建epoll实例
p_tcp->epoll_fd = epoll_create1(0);
if (p_tcp->epoll_fd == -1)
{
perror("epoll_create1 failed");
close(p_tcp->socket_fd);
return 1;
}
// 将监听socket添加到epoll实例中
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = p_tcp->socket_fd;
if (epoll_ctl(p_tcp->epoll_fd, EPOLL_CTL_ADD, p_tcp->socket_fd, &ev) == -1)
{
perror("epoll_ctl failed");
close(p_tcp->socket_fd);
close(p_tcp->epoll_fd);
return 1;
}
p_tcp->isListen = 1;
p_tcp->status = 1; // 表示在线
printf("Server is listening on %s:%d\n", p_tcp->ip, p_tcp->port);
return 0;
}
/*****************************************************************************
* @brief tcp驱动
* @param[in] p_tcp: tcp驱动结构体指针
* @return 0- 1-
*****************************************************************************/
int drvTcpServerClose(tcp_server_lib_t* p_tcp)
{
if (p_tcp == NULL || p_tcp->socket_fd < 0)
{
return 1;
}
// 关闭所有已连接的客户端
for (int i = 0; i < p_tcp->nClient; i++)
{
if (p_tcp->clients[i].fd >= 0)
{
close(p_tcp->clients[i].fd);
}
}
// 关闭服务器socket和epoll实例
close(p_tcp->socket_fd);
close(p_tcp->epoll_fd);
p_tcp->isListen = 0;
p_tcp->status = 0; // 设置为离线
printf("Server closed\n");
return 0;
}
/*****************************************************************************
* @brief tcp驱动发送
* @param[in] p_tcp: tcp驱动结构体指针
* @return 0- 1-
*****************************************************************************/
ssize_t drvTcpServerSend(tcp_server_lib_t* p_tcp)
{
if (p_tcp == NULL || p_tcp->send_len == 0)
{
return -1;
}
ssize_t total_sent = 0;
for (int i = 0; i < p_tcp->nClient; i++)
{
if (p_tcp->clients[i].fd >= 0)
{
ssize_t sent = send(p_tcp->clients[i].fd, p_tcp->send_buf, p_tcp->send_len, 0);
if (sent < 0 || sent != p_tcp->send_len)
{
perror("Send failed");
return -1;
}
total_sent += sent;
}
}
return total_sent;
}
/*****************************************************************************
* @brief tcp驱动接收
* @param[in] p_tcp: tcp驱动结构体指针
* @return 0- 1-
*****************************************************************************/
ssize_t drvTcpServerRecv(tcp_server_lib_t* p_tcp)
{
if (p_tcp == NULL)
{
return -1;
}
struct epoll_event events[MAX_EVENTS];
int nfds = epoll_wait(p_tcp->epoll_fd, events, MAX_EVENTS, p_tcp->timeout);
if (nfds == -1)
{
perror("epoll_wait failed");
return -1;
}
ssize_t total_recv = 0;
for (int i = 0; i < nfds; i++)
{
int fd = events[i].data.fd;
if (fd == p_tcp->socket_fd)
{
// 有新的客户端连接
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int client_fd = accept(p_tcp->socket_fd, (struct sockaddr*)&client_addr, &addr_len);
if (client_fd == -1)
{
perror("accept failed");
continue;
}
// 设置新连接为非阻塞
if (setNonblocking(client_fd) > 0)
{
close(client_fd);
continue;
}
// 添加新客户端到epoll监听
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = client_fd;
if (epoll_ctl(p_tcp->epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1)
{
perror("epoll_ctl add client failed");
close(client_fd);
continue;
}
// 添加到客户端列表中
if (p_tcp->nClient < MAX_CLIENTS)
{
p_tcp->clients[p_tcp->nClient].fd = client_fd;
p_tcp->clients[p_tcp->nClient].client = client_addr;
p_tcp->nClient++;
printf("New client connected\n");
}
else
{
printf("Max clients reached\n");
close(client_fd);
}
}
else
{
// 接收客户端数据
ssize_t recv_len = recv(fd, p_tcp->recv_buf, MAX_TCP_LEN, 0);
if (recv_len < 0)
{
if (errno != EWOULDBLOCK && errno != EAGAIN)
{
perror("Receive failed");
close(fd);
epoll_ctl(p_tcp->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
}
}
else if (recv_len == 0)
{
// 客户端断开连接
close(fd);
epoll_ctl(p_tcp->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
printf("Client disconnected\n");
}
else
{
total_recv += recv_len;
p_tcp->recv_len = recv_len; // 更新接收数据的长度
}
}
}
return total_recv;
}