Routing packets to the right client
12/13/2005 1:58:16 AM Megahertz GDNet+ Member since: 10/19/2000 From: USA (http://www.gamedev.net/community/forums/topic.asp?topic_id=363744) post a thread to discuss this problem "Routing packets to the right client". the requirement of why we need a user object is that we need to store some information about this socket, for example, IP address, port, the data buffer that hasn't been sent and so on. recently, I am searching a solution of this problem, the common and fixable solution is use map(BR-tree or hash table): [map solution] buld a hash table, the key is the socket ID (aslo named file decriber, fd), the value is the user object(eg. Socket object). if an event occurs, the kernel will deliever a fd, then use the fd as key to find the Socket object. class Socket { public: int fd; // socket ID public: char * data; // buffer with this socket public: int IPv4; // ip address with int form ... }; std::map<int, Socket *> sock_map; Socket * obj = sock_map[fd]; use BT-tree will cost O(logN) to find the Socket object, and hash table normally cost O(1), but has table will cost more time when insert new key-value pair to the map, and the time cost of hash function can't be ignored. there are another solution that use Linux kernel 2.55 upper epoll. [epoll solution] see the epoll man page of epoll_wait, there are some statements need to care, that is: http://www.die.net/doc/linux/man/man2/epoll_wait.2.html "The data of each returned structure will contain the same data the user set with a epoll_ctl(2) (EPOLL_CTL_ADD,EPOLL_CTL_MOD) while the events member will contain the returned event bit field. " the data fields is 64-bits data, in 32-bits platform the left 32-bits can be used as Object pointer, and when event occurs, the kernel will tell us what is the fd with the Object pointer. the follow code has been tested with Redhat Advanced Server 4, hope that it will be useful. /** @author : bsmith, bsmith@qq.com @date : 2006-08-10 */ #include <sys/epoll.h> #include <sys/socket.h> #include <sys/epoll.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> const int MAX_LEN = 10; class Socket { public: Socket() { fd = -1; len = 0; } public: int fd; public: char data[MAX_LEN]; public: int len; }; void setnonblocking(int sock) { int opts; opts=fcntl(sock,F_GETFL); if(opts<0) { printf("[setnonblocking] error\n"); } opts = opts|O_NONBLOCK; if(fcntl(sock,F_SETFL,opts)<0) { printf("[setnonblocking] error\n"); } } struct hash_epoll_data { int fd; void * ptr; }; struct hash_epoll_event { __uint32_t events; struct hash_epoll_data data; }; void run() { const int MAX_NFDS = 100000; const int MAX_EVENTS = 100; struct sockaddr_in addr; int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(5555); bind(sock, (struct sockaddr *)&addr, sizeof(addr)); listen(sock, 10); int epfd = epoll_create(MAX_NFDS); struct hash_epoll_event ev; ev.data.fd = sock; ev.data.ptr = (void *)0x12345; ev.events = EPOLLIN|EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, sock, (struct epoll_event *)&ev); int nfds; int fd; socklen_t addrlen; Socket * client; struct hash_epoll_event events[MAX_EVENTS]; for (;;) { nfds = epoll_wait(epfd, (struct epoll_event*)events, MAX_EVENTS, 2000); printf("[wait] nfds = %d\n", nfds); for (int i = 0;i < nfds;i ++) { if (events.data.fd == sock) { printf("[listen] ptr = %08x\n", (int)(events.data.ptr)); fd = accept(sock, (sockaddr *)&addr, &addrlen); setnonblocking(fd); if (fd >= 0) { client = new Socket(); printf("[listen] client = %08x\n", (int)(client)); client->fd = fd; ev.data.fd = fd; ev.data.ptr = client; ev.events = EPOLLIN|EPOLLOUT|EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, fd, (struct epoll_event *)&ev); } } else if (events.events&EPOLLIN) { printf("[client in] ptr = %08x\n", (int)(events.data.ptr)); client = (Socket *)events.data.ptr; client->len = recv(events.data.fd, client->data, MAX_LEN, 0); printf("[recv] len=%d\n", client->len); } else if (events.events&EPOLLOUT) { printf("[client out] ptr = %08x\n", (int)(events.data.ptr)); client = (Socket *)events.data.ptr; if (client->len > 0) { client->len = send(client->fd, client->data, client->len, 0); } printf("[send] len=%d\n", client->len); } } } } PS: forgive me for my poor english.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement