尝试写了个稍微大一点的东西 。。遇到最坑爹的 BUG 就是 read 和 recv 的行为不一样 使用 read 就没事。。。无解 以后再也不用 recv 了。。。。单线程的好处就是不需要使用锁 所有操作全都为异步 不能作为异步的部分 应该使用队列来和异步操作的部分做桥接。
/*
实现一个单线程的 服务器
*/
#define __FD_SETSIZE 65535
#include "main.h"
#include "ss.h"
#include "buffer.h"
#define dbg_msg(fmt,msg...) do{\
printf( "%s::%d::%s():" fmt,__FILE__,__LINE__, __FUNCTION__,##msg ); \
}while(0);
struct buffer_list
{
struct list_head list;
buffer_context buffer;
};
struct client_list
{
struct list_head list;
int fd;
struct sockaddr_in addr;
socklen_t addr_len;
};
struct server_context
{
u_int16_t port;
int fd;//监听的 fd
int epoll_fd;
struct sockaddr_in addr;
int addr_len;
struct buffer_list buffer_pool;
struct client_list clients;
};
/*
*/
buffer_context *server_alloc_buffer(struct server_context *context)
{
buffer_context *buffer;
struct list_head *p, *n;
if (list_empty(&context->buffer_pool.list))
{
//链表是空的
buffer = &((struct buffer_list *)malloc(sizeof(struct buffer_list)))->buffer;
buffer_init(buffer);
}
else
{
list_for_each_safe(p, n, &context->buffer_pool.list)
{
buffer = &list_entry(p, struct buffer_list, list)->buffer;
buffer_clean(buffer);
list_del_init(&context->buffer_pool.list); // <--- 貌似 init 很有必要啊
break;
}
}
dbg_msg("get buffer : %x \n", (u_int32_t)buffer);
return buffer;
}
/*
把这个 buffer 放回 pool 里
*/
void server_free_buffer(struct server_context *server, buffer_context *buffer)
{
struct buffer_list *list = list_entry(buffer, struct buffer_list, buffer);
dbg_msg("try to free buffer : %x \n", (uint32_t)buffer);
assert(&list->buffer == buffer);
list_add(&list->list, &server->buffer_pool.list);
}
void server_insert_client(struct server_context *server, struct client_list *client)
{
list_add(&client->list, &server->clients.list);
}
int server_remove_client(struct server_context *server, struct client_list *client)
{
int ret = -1;
struct list_head *p, *n;
dbg_msg("remove socket %d \n", client->fd);
list_for_each_safe(p, n, &server->clients.list)
{
struct client_list *tmp = list_entry(p, struct client_list, list);
if (tmp == client)
{
list_del_init(p);
free(tmp);
ret = 1;
break;
}
}
if (-1 == ret)
{
dbg_msg("do not find client %x !!!!!\n", (int)client);
}
return ret;
}
int readall(int fd, buffer_context *buffer)
{
int err;
for (;;)
{
unsigned char buff[8192];
err = read(fd , buff, 8192);//MSG_WAITALL);
if (err < 0)
{
if (errno == EAGAIN )
break;
dbg_msg("cause error : %d %s \n", errno, strerror(errno));
}
else if (err > 0)
{
buffer_write(buffer, buff, err);
}
else
{
// == 0 ?? 此时是断开了 。。
dbg_msg("recv == 0 %d %s \n", errno, strerror(errno));
break;
}
}
return err;
}
void set_fd_noblock(int fd)
{
int flags;
flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
}
int add2epoll(int epoll_fd, int fd, void *ptr)
{
struct epoll_event ev;
dbg_msg("epoll add fd %d \n", fd);
//ev.data.fd = fd;
ev.data.ptr = ptr;
ev.events = EPOLLIN ;
return epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
}
int del_from_epoll(int fd, int epoll_fd)
{
return epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
}
int server_start(struct server_context *context, uint16_t port)
{
int ret = -1;
int fd = socket(AF_INET, SOCK_STREAM , IPPROTO_TCP);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = 0x0;
if (-1 != bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)))
{
int epoll_fd;
/* int yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
*/
set_fd_noblock(fd);
if (-1 != (epoll_fd = epoll_create(100)))
{
add2epoll(epoll_fd, fd, context);
context->epoll_fd = epoll_fd;
context->fd = fd;
context->port = port;
INIT_LIST_HEAD(&context->clients.list);
INIT_LIST_HEAD(&context->buffer_pool.list);
listen(fd, 1);
ret = 1;
}
else
{
close(fd);
dbg_msg("epoll %d %s ", errno, strerror(errno));
}
}
else
{
dbg_msg("bind failed %d:%s \n", errno, strerror(errno));
close(fd);
ret = -1;
}
return ret;
}
int server_stop()
{
return -1;
}
int server_loop(struct server_context *context)
{
int nr_events;
struct epoll_event events;
while (1)
{
int i = 0;
memset(&events, 0, sizeof(struct epoll_event));
dbg_msg("enter wait.................\n");
nr_events = epoll_wait (context->epoll_fd, &events, 1, -1);
if (errno != 0)
dbg_msg("epoll_wait return errno : %d %s\n", errno, strerror(errno));
if (nr_events < 0)
{
dbg_msg("epoll_wait \n");
getchar();
}
if (events.events & EPOLLERR)
{
if (context == events.data.ptr)
{
dbg_msg("EPOLLERR on server socket !!!!!!!!!!! \n");
getchar();
}
else
{
struct client_list *client = events.data.ptr;
dbg_msg("recv EPOLLERR remote close ?! \n");
//close(client->fd);
//del_from_epoll(client->fd, context->epoll_fd);
//server_remove_client(context, client);
}
//continue;
}
if (events.events & EPOLLHUP) //这个事件 一直存在在集合中 不需要特别设置
{
dbg_msg("recv event EPOLLHUP !!!!! \n");
}
if (events.events & EPOLLIN)
{
//dbg_msg("epoll event EPOLLIN on fd : %x \n", events.data.fd);
/*
*/
if (events.data.ptr == context)
{
struct client_list *client = (struct client_list *)malloc(sizeof(struct client_list));
client->addr_len = sizeof(struct sockaddr_in);
dbg_msg("EPOLLIN on listen socket \n");
client->fd = accept(context->fd,
(struct sockaddr *)&client->addr,
&client->addr_len);
if (-1 == client->fd)
{
dbg_msg("accept failed : %d %s \n", errno, strerror(errno));
}
else
{
dbg_msg("accept a new client %d \n", client->fd);
server_insert_client(context, client);
set_fd_noblock(client->fd);
if (-1 == add2epoll(context->epoll_fd, client->fd, client))
{
dbg_msg("add 2 epoll failed %d %s \n", errno, strerror(errno));
getchar();
}
}
}
else
{
int ret = 0;
struct client_list *client = events.data.ptr;
dbg_msg("EPOLLIN on fd : %d \n", client->fd);
//客户端发来消息了//
buffer_context *buffer = server_alloc_buffer(context);
ret = readall(client->fd,
buffer);
if (buffer_get_length(buffer))
{
int end = 0;
buffer_write(buffer, (unsigned char *)&end, 4);
dbg_msg("recv %ld bytes\n", buffer_get_length(buffer));//, buffer_getat(buffer, 0));
server_free_buffer(context, buffer);
}
if (0 == ret)
{
del_from_epoll(client->fd, context->epoll_fd);
close(client->fd);
server_remove_client(context, client);
}
}
}
}
}
int main(int arc, char **argv)
{
struct server_context context;
server_start(&context, 1234);
server_loop(&context);
return 0;
}