Related
hello stackflow users,
so i want to send and receive my binary file using sockets in c++ and here is how i send it from server program
send(Connections[conindex], reinterpret_cast<char*>(rawData), sizeof(rawData), NULL);
and here is how my client program receives it
char raw[647680];
recv(Connection, raw, sizeof(raw), NULL);
is there any proper way than this? i want so that i don't have to hard code the size every time.
or any other alternatives etc
A rather general way to achieve this (in both C and C++) is something like this:
if (FILE *fp = fopen(filename, "rb"))
{
size_t readBytes;
char buffer[4096];
while ((readBytes = fread(buffer, 1, sizeof(buffer), fp) > 0)
{
if (send(Connections[conindex], buffer, readBytes, 0) != readBytes)
{
handleErrors();
break;
}
}
close(Connections[conindex]);
}
And on the client side:
if (FILE *fp = fopen(filename, "wb"))
{
size_t readBytes;
char buffer[4096];
while ((readBytes = recv(socket, buffer, sizeof(buffer), 0) > 0)
{
if (fwrite(buffer, 1, readBytes, fp) != readBytes)
{
handleErrors();
break;
}
}
}
Alternatives to this rather FTP-esque connection style includes sending the size of the file first, so the client will know when to stop listening instead of waiting for the disconnect.
Please note that this code is untested and merely meant to illustrate the concept.
I'm trying to send data to the connected client, even when the client did not send me a message first.
This is my current code:
while (true) {
// open a new socket to transmit data per connection
int sock;
if ((sock = accept(listen_sock, (sockaddr *) &client_address, &client_address_len)) < 0) {
logger.log(TYPE::ERROR, "server::could not open a socket to accept data");
exit(0);
}
int n = 0, total_received_bytes = 0, max_len = 4096;
std::vector<char> buffer(max_len);
logger.log(TYPE::SUCCESS,
"server::client connected with ip address: " + std::string(inet_ntoa(client_address.sin_addr)));
// keep running as long as the client keeps the connection open
while (true) {
n = recv(sock, &buffer[0], buffer.size(), 0);
if (n > 0) {
total_received_bytes += n;
std::string str(buffer.begin(), buffer.end());
KV key_value = kv_from(vector_from(str));
messaging.set_command(key_value);
}
std::string message = "hmc::" + messaging.get_value("hmc") + "---" + "sonar::" + messaging.get_value("sonar") + "\n";
send(sock, message.c_str(), message.length(), 0);
}
logger.log(TYPE::INFO, "server::connection closed");
close(sock);
}
I thought by moving the n = recv(sock, &buffer[0], buffer.size(), 0); outside the while condition that it would send the data indefinitely, but that is not what happened.
Thanks in advance.
Solution
Adding MSG_DONTWAIT to the recv function enabled non-blocking operations which I was looking for.
First I will explain, why it does not work, then I will make a proposal for solutions. Basically you will find the answer in the man7.org > Linux > man-pages and for recv specifially here.
When the function "recv" is called, then it will not return, until data is available and can be read. This behavior of functions is called "blocking". Means, the current execution thread is blocked until data has been read.
So, calling the function
n = recv(sock, &buffer[0], buffer.size(), 0);
as you did, causes the trouble. You need also to check the return code. 0 means, connection closed, -1 means error and you must check errno for further information.
You can modify the socket to work in non-blocking mode with the function fnctl and the O_NONBLOCK flag, for the lifetime of the socket. You can also use the the flag MSG_DONTWAIT as 4th parameter (flags), to unblock the function on a per-function-call base.
In both cases, if no data is available, the functions returns a -1 and you need to check errno for EAGAIN or EWOULDBLOCK.
return value 0 indicates that the connection has been closed.
But from the architecture point of view, I would not recommend to use this approach. You could use multiple threads for receiving and sending data, or, using Linux, one of select, poll or similar functions. There is even a common design pattern for this. It is called "reactor", There are also related patterns like "Acceptor/Connector" and "Proactor"/"ACT" available. If you plan to write a more robust application, then you may consider those.
You will find an implementation of Acceptor, Connector, Reactor, Proactor, ACT here
Hope this helps
I'm writing a simple server program that executes a command and sends the result to the client. I read countless examples that involve using popen(), pipe(), dup2(), fork(), etc., but none of them worked for me and they didn't explain the code very well. I also tried to do it myself, but without success. Could you please provide me with a well documented example?
Here's the code that receives commands/messages from the client:
void server_receive() {
struct sockaddr_in from;
int from_len, recv_len;
char buf[BUFLEN], path[256]; // BUFLEN = 1024
// Getting the path for the command to execute
strcpy(path, getenv("SYSTEMDRIVE"));
strcat(path, "\\WINDOWS\\System32\\tasklist.exe");
from_len = sizeof(from);
memset(buf, '\0', BUFLEN);
// Receiving the command
// I'll add some if-else statements to handle various commands, but for
// now I just need to see if I can even get one to work.
if((recv_len = recvfrom(sockt, buf, BUFLEN, 0, (struct sockaddr*) &from, &from_len)) == SOCKET_ERROR) {
printf("[ERROR] recvfrom() failed: %d.\n\n", WSAGetLastError());
} else {
printf("Packet received from %s:%d\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port));
printf("Data: %s\n\n", buf);
// Code to execute tasklist (I used _popen())
// and send everything back to the client (I used TransmitFile())
}
}
And here's the code that sends commands/messages to the server:
void client_send(char server[], unsigned short port) {
struct sockaddr_in to;
int s, to_len = sizeof(to);
char buf[BUFLEN]; // BUFLEN = 1024
char message[BUFLEN];
memset((char*) &to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_port = htons(port);
to.sin_addr.S_un.S_addr = inet_addr(server);
while(true) {
printf("Enter message: ");
gets(message);
if (sendto(sockt, message, strlen(message), 0, (struct sockaddr*) &to, to_len) == SOCKET_ERROR) {
printf("[ERROR] sendto() failed: %d.\n\n" , WSAGetLastError());
}
memset(buf, '\0', BUFLEN);
if (recvfrom(sockt, buf, BUFLEN, 0, (struct sockaddr*) &to, &to_len) == SOCKET_ERROR) {
printf("[ERROR] recvfrom() failed: %d.\n\n", WSAGetLastError());
} else {
printf("Server's response: %s\n\n", buf); /* The result of tasklist
should be outputted by this line of code, however I'm concerned about the
relatively small receive length (BUFLEN = 1024).*/
}
}
}
Needless to say that these two functions are just a part of my code.
That you mention _popen (with the leading underscore) and TransmitFile indicates that you are on Windows, which doesn't have fork or pipe or related functions.
There are many alternatives to executing commands in Windows. One is through _popen as you already mentioned (but you don't say what's wrong with that method). Others include the "classic" system CRT function. And of course the Windows native CreateProcess function. If you want to open a "document" there's the ShellExecute function.
Knowing which functions are available will help you in your search for examples. Adding the term windows to your searches will help finding Windows-specific examples and tutorials. And adding the term msdn will help finding topics on the Microsoft Developer Network.
I am new to C++ and socket programming. I studied with Beej's guide so my codes are almost same as the guide, but I am struggling really strange bugs.
First, my server's recv() returns 0. According to document, the client should gracefully close the connection for recv() to return 0. Not really in my case. It returns 0, at the same time, I still receive the data from the client. So, the way Beej's do to receive, does not work for me. Can someone explain how this can be possible?
char buf[MAXDATASIZE];
numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0);
buf[numbytes] = '\0';
the last line here, because numbytes is 0, it sweeps out all message I received. So I had to comment that out. Now, my code looks like this
char buf[MAXDATASIZE];
numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0);
//buf[numbytes] = '\0';
printf("received: %s\n", buf);
It now works with receiving some messages sent by client. However, I did some string manipulation (appending) in the client side, and then sent the message. Now, I send string length of 29 in the client side, but the server receives 41 bytes with strange characters.
What I sent: received: Login#1 Mary 123456 451912345
received: Login#1 Mary 123456 451912345ÿ>É„ÿy#ÿ>Ád
Here is how I receive in the server:
while(1) { // main accept() loop
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
char buf[MAXDATASIZE];
int numbytes;
if (numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0) == -1)
perror("recv");
//buf[numbytes] = '\0'; // this had to be commented out
printf("received: %s\n", buf); // prints out with weird characters
string msgRcved = buf;
close(new_fd);
}
This is how I send from client:
// string loginCredential is loaded with "1 Mary 123456 451912345" at this point
loginCredentials.insert(0, "Login#");
const char* msgToSend = loginCredentials.c_str();
int numbytesSent;
if (numbytesSent = send(sockfd, msgToSend, strlen(msgToSend), 0) == -1)
perror("send");
I'd like to know how my recv receives data while it returns 0 at the first place. And, I'd like to know what I am doing wrong to recv data from client/send data to server.
You have a precedence problem.
This:
if (numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0) == -1)
is equivalent to
if (numbytes = (recv(new_fd, buf, MAXDATASIZE-1, 0) == -1))
and
recv(new_fd, buf, MAXDATASIZE-1, 0) == -1
is 0 whenever recv succeeds.
The same problem is present on the sending end.
There's no reason to write such awkward and error-prone condition.
This is safer:
int numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0);
if (numbytes == -1)
perror("recv");
You have to test 'numbytes' for zero, separately, and if you get it close the socket and exit the read loop, because the peer has closed the connection. Otherwise, and assuming you have also tested for -1, you have to only process 'numbytes' bytes of the buffer. Not all of them. Otherwise you're liable to reprocess bytes you already processed. In this case that might mean restoring the line that null-terminated the buffer, or it might mean this:
printf("%.*s", numbytes, buf);
You are printing whatever garbage was in that stack-allocated buffer, not what the client sent. When recv(2) returns zero, nothing has been placed into the supplied buffer, so this is probably from some previous iteration of the loop.
Notes:
Connected TCP socket is is a bi-directional stream of bytes. This means you might send several of your "messages" and receive them in one chunk on the other side, or the other way around. Read from the socket in a loop until you have enough data to process, i.e. use explicit message separators, or pre-pend a length of your message that follows. This is your application-level protocol.
Don't mix C and C++ string handing like this. std::string has a size() method, use it instead of doing strlen( msgToSend.c_str() ).
Allocating any sizable buffers on the stack, especially ones receiving input from the network is a bad idea.
Printing, or otherwise passing further, unverified network input is a gross security violation leading to all sorts of problems.
Edit 0:
#molbdnilo's answer is the right one. I did not spot the precedence problem in the conditionals. My notes still apply though.
In got the following problem:
I made a server which is able to handle multiple connection by using select(). But select returns a client(index of FD_SET) also if the socket just got an error like "client disconnect" or whatever.
Is it possible to check a socket without calling recv(). Because to receive I need to get a buffer out of my "BufferPool"
Sample code:
int ret = recv(client, buffer_pool->get(), BUFFER_SIZE, 0);
if(ret == -1) ... // something went wrong
Well then I have to release the buffer again, and it was pretty much a waste of one buffer in my pool. (for a short time)
So isn't it possible to check the socket without calling recv()
I am not sure about the Windows, but using getsockopt() works like a charm on POSIX-compliant systems. Though before you use it - make sure that getting your buffer from the pool is more expensive than making an extra system call. Here is a code snippet:
int my_get_socket_error(int fd)
{
int err_code;
socklen_t len = sizeof(err_code);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err_code, &len) != 0)
err_code = errno;
else
errno = err_code;
return err_code;
}
UPDATE:
According to this document, it seems like Windows supports it too.
No, there is no way to avoid the recv() call. If select() reports that the socket is readable, then you have to read from the socket to determine its new state. If the client disconnected gracefully, recv() will return 0, not -1. If you do not want to waste a pooled buffer, then you will have to read into a temporary local buffer first, and then if recv() returns any data, you can retrieve a pooled buffer and copy the read data into it.
Calling recv and similar function does not work directly with networking devices or something similar.
When you send or receive data, all you do is questioning OS for available data, or to put data in queue for sending. Then OS will do the other job when your code is already went further.
That is why you receive errors after next call of socket function that will "contact" OS networking layers.
It is normal to get errors on that point, and you have to deal with them.
But to prevent blocking sockets and wasting buffers, check out online techniques of implementing or ready libraries that gives you asynchronous way of working with sockets, that way you don't need to define anything before socket will trigger receive callback function where you have to do actual receiving.
As well, it is not good technique to receive big amount of data in one go, because you will face problems with merged or broken apart data through TCP layer, because it is stream based layer. It is recommended to have header in you packets (few bytes) and receive them, that way you don't need pull for header, but only after header you want to read rest of message based on length provided in header. This is just possible example.
After some minutes of work and your help I just receive 1byte before receiving the full amount:
SOCKET client = ...;
char temp = 0x00;
int len = recv(client, &temp, 1, 0);
if(len == 0)
{
// .. client error handling
return;
}
char* buffer = m_memory_pool->Get();
len = recv(client, buffer + 1, m_memory_pool->buffer_size() - 1, 0);
buffer[0] = temp;
// data handling
I tried also to set a timeout for recv() but seems that under Windows it does not work, this is my code:
...
long timeout_ms = 10;
struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))
{
interval.tv_sec = 0;
interval.tv_usec = 10000;
}
setsockopt(s_sktIx, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
...