What is the appropriate way to transfer an int over a socket in C?
What I am doing so far is:
int n = 4;
int tmp = htonl(n);
write(socket, &tmp, sizeof(tmp));
and
int tmp,n;
read(socket, &tmp, sizeof(tmp));
n = ntohl(tmp);
However, the integer received is sometimes 0. Not always, but let's say 2 out of 5 times. It is never some other value, always 0. Why?
UPDATE: Return value from read is -1 and an error is:
Resource temporarily unavailable
First of all, sizeof(int) may differ on your sender and receiver machine. So I would recommend you to use something like int32_t from stdint.h.
Also, it is not guaranteed that read(..,..,sizeof(int)) will read exactly sizeof(int) bytes - it can read nothing, or it can read less bytes. So, the correct variant will be something more like this:
int send_int(int num, int fd)
{
int32_t conv = htonl(num);
char *data = (char*)&conv;
int left = sizeof(conv);
int rc;
do {
rc = write(fd, data, left);
if (rc < 0) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
// use select() or epoll() to wait for the socket to be writable again
}
else if (errno != EINTR) {
return -1;
}
}
else {
data += rc;
left -= rc;
}
}
while (left > 0);
return 0;
}
int receive_int(int *num, int fd)
{
int32_t ret;
char *data = (char*)&ret;
int left = sizeof(ret);
int rc;
do {
rc = read(fd, data, left);
if (rc <= 0) { /* instead of ret */
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
// use select() or epoll() to wait for the socket to be readable again
}
else if (errno != EINTR) {
return -1;
}
}
else {
data += rc;
left -= rc;
}
}
while (left > 0);
*num = ntohl(ret);
return 0;
}
This should work without any problem, try this :
On the sender (Server) side :
int number_to_send = 10000; // Put your value
int converted_number = htonl(number_to_send);
// Write the number to the opened socket
write(client_socket, &converted_number, sizeof(converted_number));
On the receiver(client) side :
int received_int = 0;
return_status = read(client_socket, &received_int, sizeof(received_int));
if (return_status > 0) {
fprintf(stdout, "Received int = %d\n", ntohl(received_int));
}
else {
// Handling erros here
}
Hope this will help.
I also had the same problem and wasted 30 minutes trying to find out what I did wrong. But, finally, I found the solution. From the documentation we can see that htonl() and ntohl() functions work with 32 bit unsigned integers. So, to fix the issue, you have to use unsigned __int32 or uint32_t from <stdint.h>.
So the code will look like this:
#include <stdint.h>
uint32_t n = 4;
uint32_t tmp = htonl(n);
write(socket, &tmp, sizeof(tmp));
and:
#include <stdint.h>
uint32_t tmp,n;
read(socket, &tmp, sizeof(tmp));
n = ntohl(tmp);
Since no one mentioned sprintf
you can just convert any variable to char* using it and send
if(strcmp(buf,"movUP") == 0)
{
char* msg = calloc(1, 20);
pos.y += 0.0001f;
sprintf(msg,"NEW::POS::Y=%.4f", pos.y);
sendto(master, msg, 20, 0, (struct sockaddr*)&client, addrlen);
}
Test
movUP
NEW::POS::Y=0.0001
movUP
NEW::POS::Y=0.0002
movUP
NEW::POS::Y=0.0003
movUP
NEW::POS::Y=0.0004
Use %d for integers, %f for floats
to convert back to an integer, use atoi(char*)
to convert back to an float, use atof(char*)
before converting, be sure to use strstr() to get the float value only, starting from "0"
float myPos; // floating variable that stores Object's Position in the World
...
....
memset(buf, 0, MAXBUFFER); // clears the previous buffer
recvfrom(master, buf, MAXBUFFER, 0, (struct sockaddr*)&server, &addrlen);
char* newY = strstr(buf, "0");// NEW::POS::Y=0.0001 --->> 0.000100
myPos = atof(newY); // new object's position by the server
printf("My New Position is %.4f\n", myPos); // Out: My New Position is 0.0011 -> 0.0012 -> 0.0013 -> 0.0014.
For integers (not positions), you can use the same technique and just multiply it like
float f = 0.000002f; // that is supposed to be 2 integer value
int i = (int)(f*1000000); // now, i = 2
the above methods are totally secure
If you want a more solid converting, you can use strncpy or memcpy and cut the string starting from a given index with some length assuming that you already know the incoming buffer, but in my personal view, I don't really recommend it, specifically in connectionless sockets like this one, lots of calculations and calls for buffer length, Not easy to debug sometimes if you're not totally aware of what you're doing.
Note 1: Be careful to not include zeros in your buffer when you're waiting for a server move/position command or any
quantity variable if you're planning to use the 1st method.
Note 2: You can just send your integer or float, convert it and vice versa without needing to cut or multiply it.
May new game networking developers find this answer useful too since we can't send or receive except char* with UDP sendto(), recvfrom().
Related
I am trying to write and read Integer value into/from C socket. Sometimes ntohs() return very big values like 55000 , 32000 etc...Though client is always sending value <1500. If I run the program it happens after 10-15 minutes...Sometimes after 20-30 minutes.
Can you please check below code and tell me
Why this line getting printed ?
printf("Garbage value - ntohs problem ..Exiting... ");
// write exactly n byte
inline int write_n(int fd, char *buf, int n) {
int nwrite, left = n;
int totalwrite = 0;
while (totalwrite != n) {
if ((nwrite = write(fd, buf, left)) <= 0) {
break;
} else {
totalwrite = totalwrite + nwrite;
left -= nwrite;
buf += nwrite;
}
}
if (totalwrite == 0)
return nwrite;
return totalwrite;
}
// send exactly n byte
inline int send_n(int fd, char *buf, int n) {
int nwrite, left = n;
int totalwrite = 0;
while (totalwrite != n) {
if ((nwrite = send(fd, buf, left, MSG_NOSIGNAL)) <= 0) {
break;
} else {
totalwrite = totalwrite + nwrite;
left -= nwrite;
buf += nwrite;
}
}
if (totalwrite == 0)
return nwrite;
return totalwrite;
}
uint16_t nread, len, plength, nsend;
int MTU = 1500;
char buffer[2000];
// Server receive ( Linux 64 bit)
while (1) {
// read packet length
nread = read_n(TCP_SOCKFD, (char *) &plength, sizeof(plength));
if (nread <=0) {
break;
}
len = ntohs(plength);
if (len <=0 || len > 1500 ) {
**printf("Garbage value - ntohs problem ..Exiting... "); // WHY ?**
break;
}
// read packat data
nread = read_n(SOCKFD, buffer, len);
if (nread != len) {
break;
}
}
//---------------------
// CLIENT send ( Android 5 )
while (1) {
nread = read(tunfd, buffer, MTU);
if (nread <= 0 || nread > 1500) { // always <=1500
break;
}
plength = htons(nread);
// send packet lenght
nsend = send_n(TCP_SOCKFD, (char *) &plength, sizeof(plength));
if (nsend != sizeof(plength)) {
break;
}
// send packet data
nsend = send_n(TCP_SOCKFD, buffer, nread);
if (nsend != nread) {
break;
}
}
Thank you
We cannot tell you with certainty what's happening because you cannot provide a verifiable example. Additionally, you've not presented the implementation of read_n(), but supposing that it follows the same model as write_n() and send_n(), we can nevertheless perform some analysis.
Each of the data transfer functions returns a short count in the event that data transfer is interrupted by an error. The client code watches for this, and breaks out of its loop if it detects it. Well and good. The server code does not do this when reading plength, however. Since plength, as a uint16_t, is two bytes in size, a partial read is possible and would go unnoticed by your server code.
In your example, plength is modified only via the one read_n() call presented. Network byte order is big-endian, so the most-significant byte is read first. It is possible that the combination of that byte with the stale one left over from the previous read would represent a number exceeding 1500. For example, if a 221(0x00dd)-byte packet is followed by a 1280(0x0500)-byte packet, and a partial read occurs on the second packet size, then the combined result will be 1501(0x05dd).
I don't presently see any reason to think that the client sends data different in nature than you think it does, and I don't presently see any other way that your server code could give the appearance of receiving different data than the client sends, especially since client and server each abort at the first recognized sign of trouble.
Do note, however, that this code could still be made more robust. In particular, consider that read(), write(), and send() can fail even when there is no problem with the underlying socket or data transfer request. In particular, they can fail with EINTR if the call is interrupted by a signal, and if the socket is in non-blocking mode then they can fail with EAGAIN. There may be others. It does not seem useful to operate your socket in non-blocking mode, but you might indeed want to watch for EINTR and resume reading after receiving it.
I would also suggest that, at least during development, you emit more data about the nature of the error. Call perror(), for example, and afterward print the bad data. You might even consider logging data sent and received.
Creating a tcp client <-> server program in c for my home exam. Been running into some problems with reciev and sending data between the server and client. I'm only able to receive one byte, feks if i send "abcd" i receive "a".
(This is happening both ways since i'm using same methods for server and client)
Dont know if it is the sending part thats the problem or receiving
This is my code:
#define BUFFER_SIZE 1024
char* recived_message;
int send_data(int socket, char* data){
int offset = 0, len = strlen(data);
while (offset != len) {
int nb = send(socket, data + offset, len - offset, 0);
if (nb < 0){
perror("send");
return -1;
}
offset += nb;
}
return 0;
}
int recive(int socket){
int offset = 0;
recived_message = malloc(BUFFER_SIZE);
memset(recived_message, 0, BUFFER_SIZE);
while (offset != BUFFER_SIZE) {
int nb = recv(socket, received_message + offset, BUFFER_SIZE - offset, 0);
if(nb == -1){
perror("read");
return -1;
}else if(nb == 0){
return -1;
}
offset += nb;
}
printf("%d\n", offset);
return 0;
}
char* get_data(){
return recived_message;
}
Server side
int recive_data(int socket){
char* buffer;
if(recive(socket) != 0){
return -1;
}
*buffer = *get_data();
printf("socket %d: %s\nlength: %lu%", fd, buffer, strlen(buffer));
return 0;
}
Part of client
char* test = "abcd";
for(i=0; i<10; i++) {
send_data(sock, test);
sleep(1);
}
The problem is here
*buffer = *get_data();
You dereferences the pointer returned by get_data() to get only the first element pointer to by the pointer.
And it's worse than that, because you dereference the uninitialized variable buffer to write that single character. This will lead to undefined behavior. Also, the later functions calls using this uninitialized variable also leads to undefined behavior.
The simple solution to (almost) all your problems: Assign to the actual variable:
buffer = get_data();
And I say that the above solves almost all your problems, because what if the terminating zero of the string isn't transmitted? That will also lead to UB (Undefined Behavior). If the data you receive is always a string, then you should make sure it's terminated, preferably in the receive function:
int recive(int socket){
...
received_message[offset] = '\0';
return 0;
}
I am trying to send a long int number using sockets (from client to server).
Both the client and the server are x86 (and identical machines). The client writes 21 long int's to the socket and the server reads it out.
Here is a part of the code.
Server:
long int num = 0;
int ret;
for (int i = 0; i < 21; i++) {
if ((ret = read(sfd_client, (char *) &num, sizeof(num))) == -1) {
perror("read");
exit(1);
}
printf("number = %d = %ld ret = %d\n", i, num, ret);
}
Client:
for (int i = 0; i < 21; i++) {
if (write(sockfd_client, &temp[i], sizeof(long int)) == -1) {
exit(1);
}
}
I noticed that after calling the read the return value is exactly 8, which means that 8 bytes were read; yet the data is always 0. I don't understand what I am doing wrong. Also I was looking at various functions, and all cater to unsigned numbers but not signed (ntoh and hton family).
NOTE: Also I noticed that the first read() is 8 bytes, but the following ones are only 1 byte.
Whats the best way I can transmit all these numbers? (Also I noticed that the for loop refuses to quit if I have the read statement in there.)
Solution (The problem was the fact that the read was returning less bytes than required, This function solved it)
void read_long(int sockfd_client, char *num) {
unsigned int size = sizeof(long int);
int rlen = 0;
int ret;
while (rlen < size) {
if ((ret = read(sockfd_client, (num + rlen), size - rlen)) == -1) {
perror("read_long");
exit(1);
}
if (ret == 0) {
perror("socket closed before consumption");
exit(1);
}
rlen += ret;
}
}
[I'm going to repeat my comment as an answer, given that it turned out to be correct]
Note that calling read() with sizeof(num) returns up to sizeof(num) bytes. It might return fewer and it's your responsibility to accumulate them.
Similarly write() does not guarantee to write the requested number of bytes. You need to check the return value from write to see how many bytes were actually written, and then write the remaining bytes.
I'm trying to implement a working HTTP Client-Server application just to make practice with network programming.
The 2 programs have to follow this basic algorithm:
CLIENT - send a GET request
SERVER - send "+OK\r\n"
SERVER - send file size in bytes
SERVER - send file
CLIENT - send ACK
I'm having a lot of troubles in the reading part, probably because i perform some dirty read on the stream.
These are the 2 reading function that i'm using:
/* Reads a line from stream socket s to buffer ptr
The line is stored in ptr including the final '\n'
At most maxlen chasracters are read*/
int readline (SOCKET s, char *ptr, size_t maxlen)
{
size_t n;
ssize_t nread;
char c;
for (n=1; n<maxlen; n++)
{
nread=recv(s, &c, 1, 0);
if (nread == 1)
{
*ptr++ = c;
if (c == '\n')
break;
}
else if (nread == 0) /* connection closed by party */
{
*ptr = 0;
return (n-1);
}
else /* error */
return (-1);
}
*ptr = 0;
return (n);
}
and:
int readNumber(SOCKET s, long *num, int maxRead)
{
size_t n;
ssize_t nread;
int totRead;
long number=0;
for (n=1; n<maxRead+1; n++)
{
nread=recv(s, &number, sizeof(number), 0);
if (nread == sizeof(number))
{
totRead+=nread;
*num = number;
}
else if (nread == 0) /* connection closed by party */
{
*num = 0;
return (n-1);
}
else /* error */
{
printf("nread = %d\n", nread);
return (-1);
}
}
return (totRead);
}
this is the snippet of the main where i receive the +OK message and then the file size:
memset(rbuf,0,sizeof(rbuf)); //rbuf is the buffer where is store the read
printf("waiting for response...\n");
result = readline(s, rbuf, sizeof(rbuf)); //reading function is above
printf("Byte read(okMsg) = %d\n", result);
if (result <= 0)
//ERROR MANAGEMENT
{
printf("Read error/Connection closed\n");
closesocket(s);
SockCleanup();
exit(1);
}
else
{
long fileLength=0;
unsigned char *fBuf;
//RECEIVE OK
if(!strcmp(rbuf,"+OK\r\n"))
{
puts("+OK\n");
//RECEIVE FILE LEN
int nw = readNumber(s, &fileLength, 1); //reading function is above
printf("Byte read(fDim) = %d\n", nw);
printf("File is %ld bytes long\n", fileLength);
if(nw >0)
{
// RECEIVE FILE
}
}
}
When i send the "+OK\r\n" string the server tells me that it sends 8 bytes, but when i read i find the '\0' char only after 6 bytes.
By the way it reads correctly the message, but when i try to read the file size (that is a long) it gives me back a wrong number.
My opinion is that the stream buffer is dirty, and that i'm reading 2 bytes that are not part of the file size, but i'm not understanding why this happens.
Please ask me more info if i'm not clear enough.
SOLVED:
Thank you all for your answers!!!
You put me in the right mindset to understand what was wrong.
Look like the problem was this declaration in the server:
char *okMsg = "+OK\r\n";
instead of
char okMsg[] = "+OK\r\n";
that lead me to an undefined behavior.
long number=0;
for (n=1; n<maxRead+1; n++)
{
nread=recv(s, &number, sizeof(number), 0);
You forgot to design and implement a protocol to carry the data between your server and your client. Because TCP provides a stream of bytes, your protocol should be defined as a stream of bytes.
How many bytes convey this number? Is "however many bytes a 'long' happens to occupy on my platform" a good answer? What's the semantic meaning of the first byte? Is "whatever the first byte of a 'long' happens to mean on my platform" a good answer?
A good answer would be, "The size shall be conveyed as a 4-byte unsigned integer in little-endian byte order". Then make absolutely sure your code sends and receives in that format.
I was searching for hours to get an answer about my question, but didnt find anything. Maybe I get some help here.
What I'm trying to do:
A Java-Client sends a message to a C-Server. The message contains different types like integer, short and also a string (e.g. message = int: total_msg_length; short: operation; string: hello --> total_msg-length=4 (size of integer), operation = 2 (size of short), hello = 5 (each letter is 1 byte=5).
So, how can I receive the message in my server? The code below receives an Integer (works fine). Next step will be to receive a short and then a string (converted in US-ASCII).
int *msg;
int recv_size;
int final_msg;
if( (recv_size = recv(client_socket, &msg, sizeof(msg), 0 )) < 0 ){
error_exit("Fehler bei recv(message_len)");
}
final_msg = endian_swap(msg);
printf("Message: %d\n", final_msg);
return final_msg;
Is there a way to use a byte array instead of char buffer? Im thankful for every help. Please excuse my bad english, I'm from germany :-)
You need to create a generic "read_n_bytes" function.
This you can use to read the message-size, the operation and the text, in three successive calls.
Those three calls you then wrap in a function to be called to read an entire message.
A generic reader might look like this:
/*
* Reads n bytes from sd into where p points to.
*
* returns 0 on succes or -1 on error.
*
* Note:
* The function's name is inspired by and dedicated to "W. Richard Stevens" (RIP).
*/
int readn(int sd, void * p, size_t n)
{
size_t bytes_to_read = n;
size_t bytes_read = 0;
while (bytes_to_read > bytes_read)
{
ssize_t result = read(sd, p + bytes_read, bytes_to_read);
if (-1 == result)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
continue;
}
# ifdef DEBUG
{
int errno_save = errno;
perror("read() failed");
errno = errno_save;
}
# endif
break;
}
else if(0 == result)
{
# ifdef DEBUG
{
int errno_save = errno;
fprintf(stderr, "%s: Connection closed by peer.", __FUNCTION__);
errno = errno_save;
}
# endif
break;
}
bytes_to_read -= result;
bytes_read += result;
}
return (bytes_read < bytes_to_read) ?-1 :0;
}