【发布时间】:2013-08-30 04:50:13
【问题描述】:
我的 tcp 服务器有问题。我想监听多个端口以响应客户端。它应该是一种基于事件的。每个端口表示另一种类型的响应。我读了很多关于 epoll、poll、select 或多线程的文章。我尝试使用 Unix Network Programming 等书籍中的大量示例。但可能我需要一些触发关键字。怎样才能正常启动?
希望我的问题很容易理解。 感谢每个答案!
缩小范围,这是我的想法... 我开始考虑这个:
如果我有一个包含很多服务器的“服务器管理器”,我可以按照以下方式进行操作吗?
CreateSockets(ServerList); CheckSockets(SocketList, master_set);
在服务器管理器中: 1)for循环创建所有服务器socket(函数:socket/setsockopt/ioctl/bind/listen)
void CreateSockets(map<int,ServerType> ServerList)
{
fd_set master_set;
map<int,ServerType>::iterator it;
map<int,int> SocketList;
for (it= ServerList.begin();it!= ServerList.end();it++)
{
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sd < 0)
{
perror("socket() failed");
exit(-1);
}
rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (rc < 0)
{
perror("setsockopt() failed");
close(listen_sd);
exit(-1);
}
rc = ioctl(listen_sd, FIONBIO, (char *)&on);
if (rc < 0)
{
perror("ioctl() failed");
close(listen_sd);
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = ((*it).second->Port);
rc = bind(listen_sd,(struct sockaddr *)&addr, sizeof(addr));
if (rc < 0)
{
perror("bind() failed");
close(listen_sd);
exit(-1);
}
rc = listen(listen_sd, 32);
if (rc < 0)
{
perror("listen() failed");
close(listen_sd);
exit(-1);
}
SocketList.insert(make_pair(((*it).second->Port),listen_sd));
FD_ZERO(&master_set);
max_sd = listen_sd;
FD_SET(listen_sd, &master_set);
}
}
下一步: 2) 一些如何在服务器管理器中等待某些事件(使用套接字描述符列表选择)
void CheckSockets(map<int,int> SocketList, fd_set master_set)
{
fd_set working_set;
do
{
memcpy(&working_set, &master_set, sizeof(master_set));
ready_descriptors = select(max_sd + 1, &working_set, NULL, NULL, NULL);
if (ready_descriptors >0)
{
desc_ready = rc;
for (i=0; i <= max_sd && desc_ready > 0; ++i)
{
if (FD_ISSET(i, &working_set))
{
desc_ready -= 1;
if (i == listen_sd)
{
do
{
new_sd = accept(listen_sd, NULL, NULL);
if (new_sd < 0)
{
//error
}
FD_SET(new_sd, &master_set);
if (new_sd > max_sd)
max_sd = new_sd;
} while (new_sd != -1);
}
else
{
do
{
//Go into server and recv and send ( Input Parameter = i)
CheckServer(i);
} while (TRUE);
}
}
}
}
else {endserver=true;}
}while(endserver=true;)
}
3) 进入服务器并处理问题(recv/send)????
void CheckServer( int sd)
{
rc = recv(sd, buffer, sizeof(buffer), 0);
//some stuff in between
rc = send(i, buffer, len, 0);
}
这行得通吗?
IBM 非阻塞 IO 源代码使用和更改了某些部分。
感谢您的所有帮助。我能够完成一些事情,但有一件事仍然不起作用。
到目前为止我做了什么:
1) 单个服务器的构造器包括socket操作。 2)我能够返回套接字ID并将其保存在服务器管理器中。 3) 管理器有一个 for 循环,其中包含用于检查套接字上的任何事件的 select 命令。 4) 如果有什么事情发生,所有受影响的socket都会依次响应。
我的问题是:
如果我在从服务器请求数据时始终连接和断开连接,它工作正常。 当我的客户端配置为保持连接时,一切都会阻塞,因为我的代码正在等待断开连接。
这里是每个部分的代码sn-ps:
1)
Server::Server()
{
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
ret = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR,(char *)&on, sizeof(on));
ret = ioctl(listen_sd, FIONBIO, (char *)&on);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(Server_Port);
ret = bind(listen_sd,(struct sockaddr *)&addr, sizeof(addr));
ret = listen(listen_sd, 32);
Socket = listen_sd;
}
2)
Socket= new_Server->GetSocket();
SocketList.insert(make_pair(Socket,new_Server->ServerID));
3)
while (TRUE)
{
FD_ZERO(&working_set);
for (i=0;i < max_conn;i++)
{
if (SocketArray[i] >= 0) {FD_SET(SocketArray[i], &working_set);}
}
ret = select(max_sd+1, &working_set, NULL, NULL, NULL);
desc_ready= ret;
for (i=0; i <= max_sd && desc_ready > 0; ++i)
{
if (FD_ISSET(i, &working_set)) //jeder Peer der was hat
{
desc_ready -= 1;
//delete all loops to get the correct object
(Server).second->DoEvent(i);
}
}
}
4)
new_sd = accept(new_sd, NULL, NULL);
if (new_sd < 0)
{
if (errno != EWOULDBLOCK)
{
perror(" accept() failed");
}
}
do
{
rc = recv(new_sd, buffer, sizeof(buffer), 0);
//edit datastream and create response
rc = send(new_sd, buffer, len, 0);
if (rc < 0)
{
perror(" send() failed");
close_conn = TRUE;
break;
}
}while (TRUE);
我只是删除了errorhandling dor listen/bind等,只是为了缩短这里的代码......原来它在那里。
【问题讨论】:
-
这个问题太笼统了,请缩小到可以回答的范围内。
-
您已经签出Beej's Guide to Network Programming 了吗?它具有所有基础知识(不过是 c 风格)。
-
看看反应堆模式...
-
我想知道是否还没有一些类/库。
-
我需要非阻塞服务器套接字。我想编程的内容:1)建立所有必要的套接字2)在一个或多个这些套接字上等待事件3)如果事件而不是响应这些特定套接字上的每个请求......我的问题是将这个想法转换成源代码,因为我不确定哪些命令最适合我......同时考虑运行时、响应时间和最大套接字数量的限制......希望我把它缩小一点