Can I create a chat program with IOCP? - c++

I've just entered socket programming.
But I was given homework to implement a simple chat program with IOCP.
WSASend(), which is used in IOCP, forwards data to only one client connected to the socket, and how do I change this to transfer data to all connected clients?
After many attempts, the server was still transferring data only to the client that sent it.
When one client sends data to the server, I want the server to send it to all connected clients.
After many attempts, the server was still transferring data only to the client that sent it.
When one client sends data to the server, I want the server to send it to all connected clients.
This is a function that, in the IOCP program that I am currently dealing with, transfers data received to the client through a connected socket back to the client. I'm thinking about the problem here.
Of course there may be problems elsewhere. I'll show you if you want to see other parts of the code.
bool Session::SendMsg(int size) { // size : size of send data
ZeroMemory(&_sio.over, sizeof(_sio.over));
_sio.wbuf.len = size;
_sio.wbuf.buf = _sio.mbuf;
_sio.type = Iotype::Send;
DWORD trans;
// It sends data to only one client....
int ret = WSASend(_sock, &_sio.wbuf, 1, &trans, 0, &_sio.over, NULL);
if (ret == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
return false;
return true;
}

Related

User with slow data rate, slows down all other users on the server

I am developing an echo server that accepts multiple clients using the poll technique. The source code is here.
The problem I am facing is that when a client sends data to the server with a slow rate, it will slow down all other clients, waiting for the slow user to finish sending all the data first.
To overcome this problem I though about creating worker threads on the server and send each socket read there, but this would make things more complicated because I will have to use some kind of synchronisation so that not two threads will read from the same socket descriptor at the same time.
What method are you using to overcome this problem with the slow clients? Is there any design pattern for this?
Edit 1: Some code to describe the question better
Edit 2: Added a check for POLLIN before recv
//simplified code
//poll loop
do {
rc = poll(fds, nfds, -1);
//when some socket descriptors are ready for read, read them all
for (i = 0; i < nfds; i++)
{
if (fds[i].revents & POLLIN) {
//here if the fds[i] socket descriptor has a slow data rate, it will slow down all the other
//clients waiting for the server to complete the recv with the slow client.
int bytes_recv = recv(fds[i], buffer, 1024, 0);
}
}
} while (end_server == false);

Message to all connected clients(Winsock)(c++)

I have a server, which creates a separate thread for each new client
while ((client_socket = accept(server_socket, (sockaddr*)&client_info, &client_addr_size)))
{
nclients++;
HOSTENT *hst;
hst = gethostbyaddr((char*)&client_info.sin_addr.S_un.S_addr, 4, AF_INET);
printf("+%s [%s] new connect!\n", (hst) ? hst->h_name : "", inet_ntoa(client_info.sin_addr));
PRINTUSERS;
DWORD thID;
CreateThread(NULL, NULL, SexToClient, &client_socket, NULL, &thID);
}
Stream function every n seconds sends a message.(All streams do not do it at the same time).How to send a message to all clients at the same time?(broadcast)
I cant See Streamfunction. Without the corresponding function I cant give a perfect answer. Normally you would send (asynchron) in a for loop to all clients. The System would teen send the Massage to each Client one After Another. If you want to truly send a Massage to multiple clients at the Same time you need to use multicast.
(= sending one package which will arrive at multiple clients.) Unfortunately this is not possible using TCP, since TCP etablishes a (secure) point to point connection between one host and one client. You would have to use UDP. Remember that UDP wont care if the packages will arrive in the right Order, are correct or arrive at all.

Socket Client send using connection accepted by Server

Is it right method client send data using the same connection accepted by server?.
The situation is like this, I have blue tooth server running on my PC and on the other side I have android phone with client and server. From android side the client start connection. I am using blue-tooth chat example from android samples.
And the server-client on android look like
BluetoothSocket socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
And in the PC side I am using Bluez libraries to implement server and client.
The code includes blue tooth receive thread and a main thread, whenever the server accept a connection from android phone I just assign the socket value to a global variable and whenever the client need to send data it send using the same socket ,
Server:-
int GLOBAL_CLIENT;
void* recive_bluetooth_trd(void*)
{
...............................
..............................
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
GLOBAL_CLIENT=client;
while(1){
bytes_read = read(client, buf, sizeof(buf));
....................
...................
}
Client:-
void clinet(char *msg, int length){
........................
int bytes_write=write(GLOBAL_CLIENT,message, length);
..........................
}
My question is, Is it a right method ? The problem is that some times the client send data successfully from PC but not receiving on android side.
The biggest problem I see is that you won't ever leave your while(1) loop, even when the client disconnects. Read will return immediately forever with 0 bytes read (check for a return code of <= 0), trying to signal that the socket is disconnected. Your code will go into a tight infinite loop and use up all the CPU resources it can get its single-threaded hands on.
You need to make sure you ALWAYS check your socket and IO return codes and handle the errors correctly. The error handling for sockets is usually about 3x the actual socket code.
Unless of course the .......... stuff is the important bits. Always tough to tell when people hide code relevant to the question they are asking.
Seems correct to me, but after read you have to NUL ('\0') terminate your buffer if you are treating with strings:
buf[bytes_read] = '\0';

TCP connection accepted, but writing data causes it to use a stale connection

The server (192.168.1.5:3001), is running Linux 3.2, and is designed to only accept one connection at a time.
The client (192.168.1.18), is running Windows 7. The connection is a wireless connection. Both programs are written in C++.
It works great 9 in 10 connect/disconnect cycles. The tenth-ish (randomly happens) connection has the server accept the connection, then when it later actually writes to it (typically 30+s later), according to Wireshark (see screenshot) it looks like it's writing to an old stale connection, with a port number that the client has FINed (a while ago), but the server hasn't yet FINed. So the client and server connections seems to get out of sync - the client makes new connections, and the server tries writing to the previous one. Every subsequent connection attempt fails once it gets in this broken state. The broken state can be initiated by going beyond the maximum wireless range for a half a minute (as before 9 in 10 cases this works, but it sometimes causes the broken state).
Wireshark screenshot behind link
The red arrows in the screenshot indicate when the server started sending data (Len != 0), which is the point when the client rejects it and sends a RST to the server. The coloured dots down the right edge indicate a single colour for each of the client port numbers used. Note how one or two dots appear well after the rest of the dots of that colour were (and note the time column).
The problem looks like it's on the server's end, since if you kill the server process and restart, it resolves itself (until next time it occurs).
The code is hopefully not too out-of-the-ordinary. I set the queue size parameter in listen() to 0, which I think means it only allows one current connection and no pending connections (I tried 1 instead, but the problem was still there). None of the errors appear as trace prints where "// error" is shown in the code.
// Server code
mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
if (mySocket == -1)
{
// error
}
// Set non-blocking
const int saveFlags = ::fcntl(mySocket, F_GETFL, 0);
::fcntl(mySocket, F_SETFL, saveFlags | O_NONBLOCK);
// Bind to port
// Union to work around pointer aliasing issues.
union SocketAddress
{
sockaddr myBase;
sockaddr_in myIn4;
};
SocketAddress address;
::memset(reinterpret_cast<Tbyte*>(&address), 0, sizeof(address));
address.myIn4.sin_family = AF_INET;
address.myIn4.sin_port = htons(Port);
address.myIn4.sin_addr.s_addr = INADDR_ANY;
if (::bind(mySocket, &address.myBase, sizeof(address)) != 0)
{
// error
}
if (::listen(mySocket, 0) != 0)
{
// error
}
// main loop
{
...
// Wait for a connection.
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(mySocket, &readSet);
const int aResult = ::select(getdtablesize(), &readSet, NULL, NULL, NULL);
if (aResult != 1)
{
continue;
}
// A connection is definitely waiting.
const int fileDescriptor = ::accept(mySocket, NULL, NULL);
if (fileDescriptor == -1)
{
// error
}
// Set non-blocking
const int saveFlags = ::fcntl(fileDescriptor, F_GETFL, 0);
::fcntl(fileDescriptor, F_SETFL, saveFlags | O_NONBLOCK);
...
// Do other things for 30+ seconds.
...
const int bytesWritten = ::write(fileDescriptor, buffer, bufferSize);
if (bytesWritten < 0)
{
// THIS FAILS!! (but succeeds the first ~9 times)
}
// Finished with the connection.
::shutdown(fileDescriptor, SHUT_RDWR);
while (::close(fileDescriptor) == -1)
{
switch(errno)
{
case EINTR:
// Break from the switch statement. Continue in the loop.
break;
case EIO:
case EBADF:
default:
// error
return;
}
}
}
So somewhere between the accept() call (assuming that is exactly the point when the SYN packet is sent), and the write() call, the client's port gets changed to the previously-used client port.
So the question is: how can it be that the server accepts a connection (and thus opens a file descriptor), and then sends data through a previous (now stale and dead) connection/file descriptor? Does it need some sort of option in a system call that's missing?
I'm submitting an answer to summarize what we've figured out in the comments, even though it's not a finished answer yet. It does cover the important points, I think.
You have a server that handles clients one at a time. It accepts a connection, prepares some data for the client, writes the data, and closes the connection. The trouble is that the preparing-the-data step sometimes takes longer than the client is willing to wait. While the server is busy preparing the data, the client gives up.
On the client side, when the socket is closed, a FIN is sent notifying the server that the client has no more data to send. The client's socket now goes into FIN_WAIT1 state.
The server receives the FIN and replies with an ACK. (ACKs are done by the kernel without any help from the userspace process.) The server socket goes into the CLOSE_WAIT state. The socket is now readable, but the server process doesn't notice because it's busy with its data-preparation phase.
The client receives the ACK of the FIN and goes into FIN_WAIT2 state. I don't know what's happening in userspace on the client since you haven't shown the client code, but I don't think it matters.
The server process is still preparing data for a client that has hung up. It's oblivious to everything else. Meanwhile, another client connects. The kernel completes the handshake. This new client will not be getting any attention from the server process for a while, but at the kernel level the second connection is now ESTABLISHED on both ends.
Eventually, the server's data preparation (for the first client) is complete. It attempts to write(). The server's kernel doesn't know that the first client is no longer willing to receive data because TCP doesn't communicate that information! So the write succeeds and the data is sent out (packet 10711 in your wireshark listing).
The client gets this packet and its kernel replies with RST because it knows what the server didn't know: the client socket has already been shut down for both reading and writing, probably closed, and maybe forgotten already.
In the wireshark trace it appears that the server only wanted to send 15 bytes of data to the client, so it probably completed the write() successfully. But the RST arrived quickly, before the server got a chance to do its shutdown() and close() which would have sent a FIN. Once the RST is received, the server won't send any more packets on that socket. The shutdown() and close() are now executed, but don't have any on-the-wire effect.
Now the server is finally ready to accept() the next client. It begins another slow preparation step, and it's falling further behind schedule because the second client has been waiting a while already. The problem will keep getting worse until the rate of client connections slows down to something the server can handle.
The fix will have to be for you to make the server process notice when a client hangs up during the preparation step, and immediately close the socket and move on to the next client. How you will do it depends on what the data preparation code actually looks like. If it's just a big CPU-bound loop, you have to find some place to insert a periodic check of the socket. Or create a child process to do the data preparation and writing, while the parent process just watches the socket - and if the client hangs up before the child exits, kill the child process. Other solutions are possible (like F_SETOWN to have a signal sent to the process when something happens on the socket).
Aha, success! It turns out the server was receiving the client's SYN, and the server's kernel was automatically completing the connection with another SYN, before the accept() had been called. So there definitely a listening queue, and having two connections waiting on the queue was half of the cause.
The other half of the cause was to do with information which was omitted from the question (I thought it was irrelevant because of the false assumption above). There was a primary connection port (call it A), and the secondary, troublesome connection port which this question is all about (call it B). The proper connection order is A establishes a connection (A1), then B attempts to establish a connection (which would become B1)... within a time frame of 200ms (I already doubled the timeout from 100ms which was written ages ago, so I thought I was being generous!). If it doesn't get a B connection within 200ms, then it drops A1. So then B1 establishes a connection with the server's kernel, waiting to be accepted. It only gets accepted on the next connection cycle when A2 establishes a connection, and the client also sends a B2 connection. The server accepts the A2 connection, then gets the first connection on the B queue, which is B1 (hasn't been accepted yet - the queue looked like B1, B2). That is why the server didn't send a FIN for B1 when the client had disconnected B1. So the two connections the server has are A2 and B1, which are obviously out of sync. It tries writing to B1, which is a dead connection, so it drops A2 and B1. Then the next pair are A3 and B2, which are also invalid pairs. They never recover from being out of sync until the server process is killed and the TCP connections are all reset.
So the solution was to just change a timeout for waiting on the B socket from 200ms to 5s. Such a simple fix that had me scratching my head for days (and fixed it within 24 hours of putting it on stackoverflow)! I also made it recover from stray B connections by adding socket B to the main select() call, and then accept()ing it and close()ing it immediately (which would only happen if the B connection took longer than 5s to establish). Thanks #AlanCurry for the suggestion of adding it to the select() and adding the puzzle piece about the listen() backlog parameter being a hint.

TCP IOCP won't receive after acceptex

I'm trying to write an IOCP server. Basically, I have it accepting new connections. For the purpose of my testing, I'm running and connecting to 127.0.0.1.
I create the pseudo socket prior to calling AcceptEx(). Once a connection is accepted, the new pseudo socket is used for communication. This new socket is associated with an io completion port [CreateIoCompletionPort], I then assign it a few options, [SO_EXCLUSIVEADDRUSE] and [SO_CONDITIONAL_ACCEPT], and then I call WSARecv() to accept incoming data.
The problem is that once my remote connection connects to the server, it sends data, but that data is never received. I'm wondering if someone could offer some ideas as to why it's not receiving data? Perhaps my logic is flawed? I stepped through my code several times. no errors are recorded.
EDIT: Fixed the wording. I create the socket before AcceptEx() call.
Basic logic in my code:
// Create socket, associate with IOCP
WSASocket(af, type, proto, lpProtoInfo, g, dwFlags);
HANDLE hIOCP = GetPool()->GetQueueHandle();
CreateIoCompletionPort(hSource, hIOCP, 0, 0) != NULL;
// Server bind and listen
bind(m_shSocket, pAddr, nAddrLen);
listen(m_shSocket, nBacklog);
// Creation of the pseudo socket
SOCKET s = ::WSASocket(m_iSocketAf, m_iSocketType, m_iSocketProto, m_pWpi, m_SocketGroup, m_dwSocketFlags);
DWORD dwBytes;
BOOL bRet = m_fnAcceptEx(m_shSocket, s, chOutput, 0, sizeof(SOCKADDR_STORAGE) + 16, sizeof(SOCKADDR_STORAGE) + 16, &dwBytes, m_pcbAccept);
// ... New Connection comes in, it's accepted ...
// Associate new pseudo socket with IOCP
HANDLE hNewIOCP = GetPool()->GetQueueHandle();
CreateIoCompletionPort((HANDLE) s, hNewIOCP , 0, 0) != NULL;
// ... Remote socket sends ...
// ... Remote socket and Pseudo socket call WSARecv ...
// ... Pseudo socket does not receive ...
NOTE: I tried sending from the pseudo socket to the remote socket, same problem as sending data in the reverse way.
You need to post some code but your description doesn't make sense. That's NOT how AcceptEx() based servers operate.
With an AcceptEx() based server you create your accepted socket before you post the AcceptEx(). You then post the AcceptEx() with the listening socket and the new socket and a buffer which allows you to receive the remote address and, optionally, data.
So if you are describing your code in your original question then your code is wrong or you're not using AcceptEx(). I'm currently ignoring the 'few options' that you throw into the mix as they simply further confuse things at present without any code to analyse.
You might be interested in downloading my free IOCP based server framework, which includes working AcceptEx() and traditional Accept() based server code. You can get it from here: http://www.serverframework.com/products---the-free-framework.html
Are you calling GetQueuedCompletionStatus to get the data?
In case you are not doing this just to learn for yourself, I would also recommend that you use boost::asio - an excellent library that allows you to let someone else do the tedious code for handling the io completion ports.
I figured it out. I'm an idiot. I was sending zero bytes.