У меня есть программа с несколькими клиентами. Сервер должен (и может) отправлять сообщения клиенту в любое время, поэтому клиент должен быть постоянно готов к приему (и отображению на своей консоли) всех сообщений, которые отправляет сервер.
В то же время клиентская консоль должна принимать входные данные для отправки на сервер для обработки (сервер служит посредником между клиентами).
Как я могу это сделать? Я работаю с кодом, взятым из http://www.codeproject.com/Articles/7785/Single-Server-With-Multiple-Clients-a-Simple-C-Imp и клиентский код (который я прилагаю ниже) работает, принимая сообщение от сервера, отправляя его на сервер, прежде чем он будет готов к приему сообщений. Как мне приспособить это, чтобы сделать то, что мне нужно?
Я включаю только основную часть клиентского кода, потому что думаю, что это может быть просто вопросом использования циклов — хотя я не могу понять, какие циклы — поэтому, пожалуйста, дайте мне знать, если я должен присоединить любой другой код.
#include "stdafx.h"#include "mySocket.h"#include "myLog.h"#include "myException.h"#include "myHostInfo.h"
myLog winLog;
void readServerConfig(string&);
void checkFileExistence(const string&);
int main()
{
//initialize the winsock library
myTcpSocket::initialize();
//get client's information (assume neither the name nor the address is given)
winLog << endl;
winLog << "retrieve the localHost [CLIENT] name and address:" << endl;
myHostInfo clientInfo;
string clientName = clientInfo.getHostName();
string clientIPAddress = clientInfo.getHostIPAddress();
cout << "name: " << clientName << endl;
cout << "address: " << clientIPAddress << endl;
winLog << " ==> name: " << clientName << endl;
winLog << " ==> address: " << clientIPAddress << endl;
//get server's IP address and name
string serverIPAddress = "";
readServerConfig(serverIPAddress);
winLog << endl;
winLog << "retrieve the remoteHost [SERVER] name and address:" << endl;
winLog << " ==> the given address is " << serverIPAddress << endl;
myHostInfo serverInfo(serverIPAddress,ADDRESS);
string serverName = serverInfo.getHostName();
cout << "name: " << serverName << endl;
cout << "address: " << serverIPAddress << endl;
winLog << " ==> name: " << serverName << endl;
winLog << " ==> address: " << serverIPAddress << endl;
//create the socket for client
myTcpSocket myClient(PORTNUM);
cout << myClient;
winLog << "client configuation: " << endl;
winLog << myClient;
// connect to the server.
cout << "connecting to the server [" << serverName << "] ... " << endl;
winLog << "connecting to the server [" << serverName << "] ... " << endl;
myClient.connectToServer(serverIPAddress, ADDRESS);
int recvBytes = 0;
while (1)
{
// send message to server
char messageToServer[MAX_MSG_LEN+1];
memset(messageToServer, 0, sizeof(messageToServer));
cout << "[SEND] ";
cin.getline(messageToServer,MAX_MSG_LEN);
winLog << "[SEND] " << messageToServer << endl;
myClient.sendMessage(string(messageToServer));
if ( !string(messageToServer).compare("Quit") || !string(messageToServer).compare("quit") )
break;
// receive message from server
/* string messageFromServer = "";
recvBytes = myClient.receiveMessage(messageFromServer);
if ( recvBytes == -99 ) break;
cout << "[RECV:" << serverName << "]: " << messageFromServer << endl;
winLog << "[RECV:" << serverName << "]: " << messageFromServer << endl;*/
}
return 1;
}
Если вы знакомы с программированием потоков, я бы предложил выделить отдельный поток для обработки входящего трафика, а другой — для исходящего трафика.
Другой вариант — использовать асинхронные сокеты.
1.После того как клиент подключается к серверу client1
, client2
а также client3
не закрывать соединение и ждать read()
2. На стороне сервера Вы можете посмотреть в pselect
а также &timeout
,
3. После того, как соединение установлено, сохраните session_fd в и массив clientId[3]
4. Теперь вы можете написать на write(client[0-2], , ...)
LOGIC—
int socks[10] = {... some client sockets...}
while(1)
{
fd_set readSet, writeSet;
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
int maxSock = -1;
for (int i=0; i<10; i++)
{
FD_SET(socks[i], &readSet);
if (socks[i] > maxSock) maxSock = socks[i];
if (IHaveDataToSendToThisSocket(i)) // implement this function as appropriate to your program
{
FD_SET(socks[i], &writeSet);
if (socks[i] > maxSock) maxSock = socks[i];
}
}
int ret = select(maxSock+1, &readSet, &writeSet, NULL, NULL);
if (ret < 0)
{
perror("select() failed");
break;
}
// Do I/O for sockets that are ready
for (int i=0; i<10; i++)
{
if (FD_ISSET(socks[i], &readSet))
{
// there is data to read on this socket, so call recv() on it
}
if (FD_ISSET(socks[i], &writeSet))
{
// this socket has space available to write data to, so call send() on it
}
}
}