我遇到了tcp服務器的問題。我想傾聽多個端口來回應客戶。它應該是一種基於事件的。每個端口都指示另一種類型的響應。我閱讀了很多關於epoll,poll,select或multithreading的內容。我試圖使用Unix網絡編程等書籍中的很多例子。但可能我需要一些觸發關鍵字。我該如何正確啓動?Linux TCP服務器 - 偵聽C++中的多個端口
希望我的問題很容易理解。 欣賞每個答案!
縮小它有我的想法...... 我開始思考這樣:
如果我有一個「服務器管理器」有很多服務器,我可以做如下?
CreateSockets(ServerList); CheckSockets(SocketList,master_set);
在服務器管理器: 1)循環創建所有的服務器套接字(功能:插座/ setsockopt的/ IOCTL /綁定/聽)
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 /發送)????
void CheckServer(int sd)
{
rc = recv(sd, buffer, sizeof(buffer), 0);
//some stuff in between
rc = send(i, buffer, len, 0);
}
可以這樣工作嗎?
某些部件從IBM非阻塞IO源代碼中使用和更改。
謝謝你的一切幫助。我能夠完成某件事,但有一件事仍然沒有奏效。
我做了什麼至今:
1)中的各個服務器的consrtuctor包括插座操作。 2)我能夠返回套接字ID並將其保存在服務器管理器中。 3)管理器有一個for循環,其中包含select命令來檢查套接字上的任何事件。 4)如果發生什麼事,所有受影響的套接字將會順序地重新發布。
我的問題是:
它工作正常,如果我總是連接和斷開,而我從服務器請求數據。 當我的客戶端配置成連接被保持的方式時,所有內容都被阻塞,因爲我的代碼正在等待斷開連接。
下面是每個部分的代碼片斷:
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);
我只是刪除了錯誤處理dor listen/bind等,只是爲了縮短代碼在這裏......原來它在那裏。
這個問題太廣泛了,請把它縮小到可以回答的地方。 – Mgetz
你有沒有看過[Beej的網絡編程指南](http://beej.us/guide/bgnet/)?它具有所有的基礎知識(儘管是c風格)。 – codeling
看看反應堆模式... – Sambuca