I am working on a small networking project using Winsock2. I am using a TCP connection and actually am working with IRC as an example since IRC is fairly simple. What I am doing is connecting to the server and sending an initial buffer so the server recognizes a connection. This works fine.
What concerns me is that I cannot write to the socket again. It seems my program hangs if I do not use shutdown() (on SD_SEND) after I send the initial buffer.
So the next data (based on RFC 1459) I want to send is the USER and NICK information, however, I feel like using shutdown() is what is causing my current issue. Is there a way to reinitialize the write socket?
Thanks!
ADDED CODE
Note that these are located within a class so it still may be slightly obscured. I am writing it into a simpler example using the elements I have. Everything is properly defined, so if I forget to define things, I apologize, but many of my recurring variables are defined for the scope of the class.
int main(int argc,char *argv[])
{
int iResult;
SOCKET Connection;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if(iResult != 0)
throw "Startup failed!";
// Prep stuff
ZeroMemory(&hints,sizeof(hints)); // This struct is defined addrinfo
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Now resolve server addr
iResult = getaddrinfo(argv[1],argv[2],&hints,&result);
if(iResult != 0)
throw "getaddrinfo() failed!";
// Now try to connect
for(ptr=result;ptr != NULL;ptr = ptr->ai_next)
{
Connection = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); // defined in that "hints" struct. argument number 2
if(Connection == INVALID_SOCKET)
{
freeaddrinfo(result);
WSACleanup();
throw "Error at socket();";
}
// Connect to server
iResult = connect(Connection, ptr->ai_addr, (int)ptr->ai_addrlen);
if(iResult != 0)
{
closesocket(Connection);
Connection = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
// Send initial buffer so server know you're there :)
iResult = send(Connection, "", 1, 0);
if(iResult == SOCKET_ERROR)
{
close();
throw "Could not send initial buffer!";
}
// Close this connection for the inital buffer
iResult = shutdown(Connection, SD_SEND);
if(iResult == SOCKET_ERROR)
{
close();
throw "Could not close initial buffer socket!";
}
bool connected = true;
// This is taken from my read function within the class
// BEGIN READ FUNCTION
iResult = 0; // Reset
std::string data = ""; // Capture the output and send it all at once!
// This only works if we're connected sweet cakes <3
if(connected)
{
do
{
iResult = recv(socket, recvbuf, BUFLEN, 0);
if(iResult > 0)
{
// Working properly
// Save all data even if there is more than BUFLEN sent
continue;
}
else if(iResult == 0)
// Connection closed properly
break;
else
printf("ERROR!");
} while(iResult > 0);
}
data += recvbuf;
ZeroMemory(&recvbuf,sizeof(recvbuf));
// Function returns std::string but essentially this is what happens
printf("%s",data.c_str());
// END READ FUNCTION
// BEGIN WRITE FUNCTION
iResult = 0; // Reset
SOCKET socket = Connection; // Write function arg 1
char *data; // Write function arg 2
iResult = send(socket,data,(int)strlen(data),0);
if(iResult == SOCKET_ERROR)
{
close();
printf("Could not write data: %ld",WSAGetLastError());
return 1;
}
// Data sent, let's close the write socket
iResult = shutdown(socket, SD_SEND);
if(iResult != 0)
{
close();
printf("Could not close write socket!");
return 1;
}
//return iResult;
// END WRITE FUNCTION
// Now that will produce "Could not write data: 0" for any value of data
// So realistically I want to send the USER and NICK data, then read
// and probably process a PING string from the server and send my PONG response
return 0;
}
I hope that clarifies things!
EDIT
I think I have figured out what is going wrong. I made the corrections listed below to my code; thanks guys. However, it's my read loop which is messing with things. Even after it has all the information it seems that it is waiting for the connection to be closed before it sends the output. Any ideas? My output currently looks like this (the bytes written/total is something I added to make sure everything was going down the wire correctly)
Bytes Written: 41
Bytes Total: 41
Data: ERROR :Closing Link: raged123[127.0.0.1] 6667 (Ping timeout)
...
:irc.foonet.com NOTICE AUTH :*** Found your hostname (cached)
PING :2ED39CE5
[A bunch of funny characters]WinSock 2.0
So it appears to have timed out because the PING did not receive PONG in time, however, I cannot send the PONG without first processing the PING request which means I would need to be able to read the output before the connection is closed. Any ideas?
May I suggest a fun document on the subject? Chapter's 6 and 7 of Beej's Guide to Network Programming
It has several examples.
There shouldn't be any need to send an "initial buffer" like you've done. The server will receive notification when a client connects, it doesn't depend on the client actually sending anything. (And in particular, the IRC protocol says that the server will start sending you stuff as soon as you connect.)
The call to shutdown() is highly suspicious. Why did you expect to need to do this? Shutting down a socket is something you do when you're done with the connection, not when you're just starting. You should remove this completely.
I'm not sure what type recvbuf is, but it looks like you're using it incorrectly. Something that can be appended to a std::string probably can't also have ZeroMemory() called on it, without one or the other of those being wrong. You also aren't using iResult which is the actual number of bytes received from the server.
Your write function also contains a call to shutdown(), which you should remove.
According to man send(2)
On success, these calls return the
number of characters sent. On error,
-1 is returned, and errno is set appropriately.
What happens is probably that send does not send the full buffer at once, you must use a loop around it.
This might not be your actual problem however since you,re sending an empty string...
I'd highly recommend using Wireshark so you can check what goes down to the wire
data += recvbuf;
This can't work. There's no way string::operator+= to know how many bytes have been received. This function expects a C-style string, not an arbitrary chunk of bytes.
But you also have a very fundamental design problem. You're expecting your program to speak the IRC protocol, but it contains no implementation of that protocol whatsoever. For example, the IRC protocol specifies a particular way that messages are delimited, and you have no code whatsoever to parse those messages.
As a result, your transition from reading to writing occurs at essentially a random time determined by the vagaries of TCP timing and how the server chooses to segment its output. Since the server is permitted to segment its output however it pleases (the protocol is clear that the client cannot rely on segmentation to parse the protocol but instead must rely on the line-oriented nature), your program's behavior is unpredictable.
Related
Going off a different post that helped explain the source of the symptoms of my issue: https://superuser.com/questions/1348102/windows-10-ephemeral-port-exhaustion-but-netstat-says-otherwise
I am having a very similar issue - except the problem is the program eating up all the ports is one I created myself.
See the top 2 results
See the top 2 results - 6072 ports used by one instance and 545 by the other - if I understand that result set correctly.
There are 2 instances listed as there are 2 instances running - this is a program that connects to a machine every 60 seconds, asks if it has information, retrieves it if it does, and then closes the connection.
It was written in C++ using winsock TCP connections.
Is there anything someone could suggest I modify to prevent this from happening?
Currently, after about a month and a half of the program running, we run into the issue of not being able to RDC into the server "due to a time and date difference" even though the time and date are perfectly in sync with the NTP server and the rest of the computers, and of course it will seize being able to connect to anything.
We can still connect to the server directly through IP address, but not hostname.
I haven't yet found any solutions to this other than rebooting the server.
The mechanism for connecting is a simple and primitive:
void Connect(string ipA)
{
// Initialize Winsock
Debug("Connecting to socket...");
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
Debug("Client: Error at WSAStartup().");
}
else
{
Debug("Client: WSAStartup() is OK.");
}
// Create a SOCKET for connecting to server
u_long mode = (u_long)0;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
GPT_ATTRIBUTE_NO_BLOCK_IO_PROTOCOL;
if (ConnectSocket == INVALID_SOCKET)
{
printf("Client: Error at socket(): %ld.\n", WSAGetLastError());
WSACleanup();
return;
}
iResult = ioctlsocket(ConnectSocket, FIONBIO, &mode);
if (iResult != NO_ERROR)
printf("ioctlsocket failed with error: %ld\n", iResult);
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr(ipA.c_str());
clientService.sin_port = htons(port);
// Connect to server.
if (connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR)
{
Debug("Connection failed...");
WSACleanup();
return;
}
else
Debug("Connection successful.");
}
This method is called with the IP address supplied as a parameter and results in a successful connection.
After that, several request-response packets are sent using these:
void SendPacket(int iResult, SOCKET ConnectSocket, const char* a)
{
Debug("Sending message to CW: " + (string)a);
iResult = send(ConnectSocket, a, strlen(a), 0);
if (iResult == SOCKET_ERROR) {
Debug("Send failed");
closesocket(ConnectSocket);
WSACleanup();
}
else
Debug("Send successful.");
}
And
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
And once we're done with the particular session, we close the connection:
void ShutDown(int iResult, SOCKET ConnectSocket)
{
iResult = shutdown(ConnectSocket, SD_SEND);
Debug("Shutting down socket...");
if (iResult == SOCKET_ERROR) {
Debug("Shutdown failed");
closesocket(ConnectSocket);
WSACleanup();
}
else
Debug("Shutdown successful.");
}
There are a couple hundred lines of code that handles the data received, but those won't be relevant as they don't deal with any sort of network connection.
To say I have no experience with C++ would be an understatement, I simply slapped this together using basic MS templates until it worked exactly as we needed it and haven't touched it since.
So if there is anything someone can point out that I could change to avoid port exhaustion, I would be very grateful.
Just to add a bit of clarity - the program will ALWAYS connect to the machine on the same port. I have tried to bind the outgoing connection (from Windows) port to the same one also, but I have been unsuccessful - wasted many hours trying to get this 1 simple thing right, but I presume that would resolve my issues.
I see that you are calling shutdown when you are done with a connection and if we consult the documentation for that we see:
The shutdown function does not close the socket. Any resources attached to the socket will not be freed until closesocket is invoked.
Which I take to mean that any ports associated with the socket remain in use.
Further down that page, we also read:
An application should not rely on being able to reuse a socket after it has been shut down. In particular, a Windows Sockets provider is not required to support the use of connect on a socket that has been shut down.
So, all-in-all, I would call closesocket instead of shutdown and then request a new socket from Winsock when you need one.
I'm sending and receiving info with a unix socket, but I do not completely understand how it works. Basically, I send a message like this:
int wr_bytes = write(sock, msg.c_str(), msg.length());
And receive message like this:
int rd_bytes = read(msgsock, buf, SOCKET_BUFFER_SIZE);
This code works perfectly with thousands of bytes, what I don't understand is, how does the read function knows when the other part is done sending the message? I tried to read the read documentation and, on my understanding read will return once it reaches EOF or the SOCKET_BUFFER_SIZE, is that correct?
So I'm guessing that when I give my string to the write function, it adds an EOF at the end of my content so the read function knows when to stop.
I'm asking this question because, I did not add any code that checks whether the other part finished sending the message, however, I'm receiving big messages (thousands of bytes) without any problem, why is that happening, why am I not getting only parts of the message?
Here is the full function I'm using to send a message to a unix socket server:
string sendSocketMessage(string msg) {
int sock;
struct sockaddr_un server;
char buf[1024];
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
throw runtime_error("opening stream socket");
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, "socket");
if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
close(sock);
throw runtime_error("connecting stream socket");
}
if (write(sock, msg.c_str(), msg.length()) < 0){
throw runtime_error("writing on stream socket");
close(sock);
}
bzero(buf, sizeof(buf));
int rval = read(sock, buf, 1024);
return string( reinterpret_cast< char const* >(buf), rval );
}
And here is my server function (a little bit more complicated, the type vSocketHandler represents a function that I call to handle requests):
void UnixSocketServer::listenRequests(vSocketHandler requestHandler){
int sock, msgsock, rval;
struct sockaddr_un server;
char buf[SOCKET_BUFFER_SIZE];
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
throw runtime_error("opening stream socket");
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, SOCKET_FILE_PATH);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
throw runtime_error("binding stream socket");
}
listen(sock, SOCKET_MAX_CONNECTIONS);
while(true) {
msgsock = accept(sock, 0, 0);
if (msgsock == -1){
throw runtime_error("accept socket");
} else {
bzero(buf, sizeof(buf));
if((rval = read(msgsock, buf, SOCKET_BUFFER_SIZE)) < 0)
throw runtime_error("reading stream message");
else if (rval == 0){
//do nothing, client closed socket
break;
} else {
string msg = requestHandler(string( reinterpret_cast< char const* >(buf), rval ));
if(write(msgsock, msg.c_str(), msg.length()) < 0)
throw runtime_error("sending stream message");
}
close(msgsock);
}
}
close(sock);
unlink(SOCKET_FILE_PATH);
}
what I don't understand is, how does the read function knows when the other part is done sending the message?
For a stream-type socket, such as you're using, it doesn't. For a datagram-type socket, communication is broken into distinct chunks, but if a message spans multiple datagrams then the answer is again "it doesn't". This is indeed one of the key things to understand about the read() and write() (and send() and recv()) functions in general, and about sockets more specifically.
For the rest of this answer I'll focus on stream oriented sockets, since that's what you're using. I'll also suppose that the socket is not in non-blocking mode. If you intend for your data transmitted over such a socket to be broken into distinct messages, then it is up to you to implement an application-level protocol by which the other end can recognize message boundaries.
I tried to read the read documentation and, on my understanding read will return once it reaches EOF or the SOCKET_BUFFER_SIZE, is that correct?
Not exactly. read() will return if it reaches the end of the file, which happens when the peer closes its socket (or at least shuts down the write side of it) so that it is certain that no more data will be sent. read() will also return in the event of any of a variety of error conditions. And read() may return under other unspecified circumstances, provided that it has transferred at least one byte. In practice, this last case is generally invoked if the socket buffer fills, but it may also be invoked under other circumstances, such as when the buffer empties.
So I'm guessing that when I give my string to the write function, it adds an EOF at the end of my content so the read function knows when to stop.
No, it does no such thing. On success, the write() function sends some or all of the bytes you asked it to send, and nothing else. Note that it is not guaranteed even to send all the requested bytes; its return value tells you how many of them it actually did send. If that's fewer than "all", then ordinarily you should simply perform another write() to transfer the rest. You may need to do this multiple times to send the whole message. In any event, only the bytes you specify are sent.
I'm asking this question because, I did not add any code that checks whether the other part finished sending the message, however, I'm receiving big messages (thousands of bytes) without any problem, why is that happening, why am I not getting only parts of the message?
More or less because you're getting lucky, but the fact that you're using UNIX-domain sockets (as opposed to network sockets) helps. Your data are transferred very efficiently from sending process to receiving process through the kernel, and it is not particularly surprising that large writes() are received by single read()s. You cannot safely rely on that always to happen, however.
I am writing the client side of the Socket. When there is something to read my code works fine but when there is nothing to read, the recv never returns. Help please.
Code:
m_socket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in dest;
if ( m_socket )
{
memset(&dest, 0, sizeof(dest)); /* zero the struct */
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr(address); /* set destination IP number */
dest.sin_port = htons(port);
if (connect(m_socket, (struct sockaddr *)&dest, sizeof(struct sockaddr)) == SOCKET_ERROR)
{
return false;
}
else
{
std::vector<char> inStartup1(2);
int recvReturn = recv(Socket, &inStartup1.at(0), inStartup1.size(), 0);
}
recv is a blocking call. This would help you:-
The recv() call is normally used only on a connected socket.It returns the length of the message on successful completion. If a message is too long to fit in the supplied buffer, excess bytes may be discarded DEPENDING on the type of socket the message is received from.
If no messages are available at the socket, the receive calls wait for a message to arrive, unless the socket is nonblocking, in which case the value -1 is returned and the external variable errno is set to EAGAIN or EWOULDBLOCK. The receive calls normally return any data available, up to the requested amount, rather than waiting for receipt of the full amount requested.
Taking this one step further, on a server this is how you would correctly handle a connection (socket or serial port does not matter):
make the socket/port non-blocking: this is the first important step; it means that recv() will read what is available (if anything) and return the number of read bytes or -1 in case of an error.
use select(), with a timeout, to find out when data becomes available. So now you wait for a certain amount of time for data to become available and than read it.
The next problem to handle is making sure you read the full message. Since there is no guarantee that the whole message will be available when you call recv(), you need to save whatever is available and go back to select() and wait for the next data to become available.
Put everything in a while(cond) construct to make sure you read all the data.
The condition in the while is the only thing left to figure out - you either know the length of the expected message or you use some delimiters to mark the end of the message.
Hope this helps!
I'm creating a client-server environment and I have just implemented UDP. I was only working and testing with a TCP connection before and then everything worked fine.
Now, if I try to send packets to the server from the client I get an error that some required fields weren't filled in which they cleary are (see code later on). I don't really have an idea why this is happening since it worked before.
One thing I guess that can be important, the receive method of the TCP socket and the UDP socket are on a different thread. (the server uses multithreading)
So, Here's some code:
The TCP Receive (part of it):
iResult = recv(m_Connections[t].socket, m_TCPRecvbuf, m_TCPRecvbuflen, 0);
// Deserialize the data
MessageID* receivedData = new MessageID();
receivedData->ParseFromArray((char*)m_TCPRecvbuf, receivedData->packetsize());
I did the size in ParseFromArray with iResult at first (which seemed to work) but I changed it so I put the size in the data itself. (which has now become receivedData->packetsize())
The UDP Receive (part of it) on a different thread:
iResult = recvfrom(m_UDPListenSocket, m_UDPRecvbuf, m_UDPRecvbuflen, 0, (struct sockaddr *)&address, &addrlen);
// Deserialize the data
MessageID* receivedData = new MessageID();
receivedData->ParseFromArray((char*)m_TCPRecvbuf, receivedData->packetsize());
This is the first creation of a packet that gets sent:
void NetworkInterface::SendLoginData(string username, string password)
{
// Create base message
// -----------------
MessageID message;
message.set_type(MessageID::Type::MessageID_Type_LOGINDATA);
// Create logindata
// ------------------
LoginData data = message.logindata();
data.set_username(username);
data.set_password(password);
// Create packet
// ----------------------
int size = message.ByteSize();
void* buffer = malloc(size);
message.set_packetsize(size);
message.set_clientid(0);
message.SerializeToArray(buffer, size);
if (m_pTCPNetworkingObject != nullptr)
m_pTCPNetworkingObject->SendData(buffer, size);
else
printf("NetworkInterface [ERROR]: No connection data was found. Please use CreateConnectionObject() first!\n");
}
The error that it gives after this is that the Type, ClientID and packetSize fields are missing but you can see those are filled in
Here's the SendData() method:
void SendData(void* data, int size)
{
// SEND DATA
int iResult;
iResult = send(m_TCPConnectSocket, (char*)data, size, 0 );
if (iResult == SOCKET_ERROR)
printf("send failed with error: %d\n", WSAGetLastError());
}
This is about all the information I can give. Any help is appreciated.
There are multiple problems:
1) deserialization:
receivedData->ParseFromArray((char*)m_TCPRecvbuf, receivedData->packetsize());
You call packetSize before it gets filled by parseFromArray, use iResult instead.
2) LoginData:
LoginData data = message.logindata();
This reads a copy of messages empty loginData, you never change message. Use
LoginData* data = message.mutable_logindata();
to get a pointer to messages loginData an modify it within message.
3) serialization:
int size = message.ByteSize();
void* buffer = malloc(size);
this uses the size of an empty message (since loginData is not set). So you never send the full message.
You have to call ByteSize() after all properties are set. This contradicts with the packetSize within your message.
Since you can't use it for deserialization anyway (see 1) you should remove this entry.
I have a C++ program, using mpi, that follows a typical client server model. Each mpi instance of the client connects to a corresponding mpi instance of the server. This has worked relatively well until I have had to do some testing with added latency (1 second of added latency to be precise).
Problem:
Sometimes one of the server processes do not think the client has connected but the client thinks it has connected. i.e. After using gdb, the server is waiting at accept() but the client has continued on past connect(). Thus, it appears the client thinks it has connected when the server does not think it has connected.
My best guess is that I need to set an sock-option somewhere, however talking to fellow programmers and googling has not yielded any helpful results.
EDIT:
There are two sets of MPI processes (so two different calls to mpirun), the accept() and connect() calls are for the sockets, which are between the two sets of MPI processes. It is openmpi.
The code (from someone else's code, actually) [reduced]:
Client (connect code): (m_socket is the actual socket)
if (-1 == m_socket)
{
perror("cannot create socket");
exit(EXIT_FAILURE);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
res = inet_pton(AF_INET, host_ip, &addr.sin_addr);
if (0 > res)
{
perror("error: first parameter is not a valid address family");
close(m_socket);
exit(EXIT_FAILURE);
}
else if (0 == res)
{
perror("error: second parameter does not contain valid IP address");
close(m_socket);
exit(EXIT_FAILURE);
}
//backoff
for (int sec = 1; sec < 20000; sec++ )
{
int ret;
if (0 == (ret = connect(m_socket, (struct sockaddr *)&addr, sizeof(addr))))
{
return;
}
sleep(1);
close(m_socket);
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
}
perror("connect failed");
close(m_socket);
exit(EXIT_FAILURE);
Server: (m_socket is the actual socket)
int socket = ::accept(m_socket, NULL, NULL);
if(socket < 0)
{
fprintf(stderr, "accept() failed: %s\n", strerror(errno));
close(m_socket);
exit(EXIT_FAILURE);
}
It looks like you're trying to do your connect/accept manually rather than with MPI. You might take a look at the example on Deino (http://mpi.deino.net/mpi_functions/MPI_Comm_accept.html) if you're trying to use MPI for your connections.
Alternatively, you might just need to look at a more general tutorial (some available here: http://www.mcs.anl.gov/research/projects/mpi/tutorial/) of MPI to get a feel for how communication works. Most of the time and application doesn't use Connect/Accept to communicate, but uses MPI Communicators to set up communication mechanisms between processes. It's a different model (SPMD as opposed to MPMD).