Read value from variable - c

I am trying to assign a string or an int to msg to send it later to a server. This code is in the client.
char msg[100];
int a;
.
.
.
bzero (msg, 100);
printf ("[client]your message: ");
fflush (stdout);
read (0, msg, 100);
/* sending message to server */
if (write (sd, msg, 100) <= 0)
{
perror ("[client]Error write() to server.\n");
return errno;
}
My question is how can I send the variable 'a', instead of writing a message from the command line.

sprintf(msg, "%d\n", a);
...
write(sd, msg, strlen(msg));
This assumes the client is expecting a string of digits (representing an integer) followed by a newline. I arbitrarly chose a newline delimiter, but you must have some convention by which the server knows what the heck you're sending.

I think you're a little confused about what is going on in your program. First, let's start with write().
The signature for the write() function is as follows:
ssize_t write(int fd, // a file descriptor
const void *buf, // a void * containing the payload
size_t count // the number of bytes of data to write
);
So what you have right now is:
read (0, msg, 100); // read from stdin a ascii message up to 100 bytes
/* sending message to server */
if (write (sd, msg, 100) <= 0) // write to a file descriptor (sd) the message
// if it works, it should return the number of bytes
// written
Now as far as I can tell, what you're saying is that you want to send the integer a instead of the char buffer msg. That's very easy to do:
int a = 0;
write(sd, &a, sizeof(a)); // send over the file descriptor "sd"
// you need a pointer for the second variable so use the &
// to get the address of a, then you need to identify
// the number of bytes to send, so use the sizeof macro
That will send a single integer over the socket.
You will likely need to be careful of endian issues using this approach for multibyte values (such as integers). From that perspective you might be better using an array of chars (shift in the values) so you know what to expect on the other end.
To be very blunt:
int a = rand(); // a random integer (assuming required headers and proper seeding)
char *msg = "Hello"; // a string
write(sd, &a, sizeof(a)); // write the integer
write(sd, msg, strlen(msg)+1); // write a string (strlen + 1 for the null terminator)

Related

How to send a size_t variable with a TCP socket in C?

I'm working on something that sends data to a TCP server, but first it is supposed to send the size of the data in 8 bytes.
That is, the server will read the first 8 bytes sent to it and cast them back into a size_t variable. My problem is, when there is a file size that doesn't use any of the top bits (i.e. 83 = 0000000S <- char's, not hex), it only sends the non-zero bytes.
This is how I do it:
void send_file_to_server(char *filename){
struct stat buf;
if (stat(filename, &buf)==-1){ exit(1); }
size_t file_size = buf.st_size;
char *filesize_string = calloc(1, 8);
filesize_string = (char*)&file_size;
//this function actually writes to the server
write_to_server((char*) filesize_string);
// will be code later on that sends the actual file using write_to_server()
}
The char* passed into my write_to_server() function has some weird behavior: it only recognizes it as a string of size 6, and it gets distorted from before it was passed in. Any advice on how to make this work is appreciated.
Note: I do not have to worry about endianness (htonl, etc.) or a differing size of size_t since this is for a project that will only ever be run on a specific VM.
Edits:
here is the other function:
void write_to_server(char *message){
ssize_t bytes_sent = 0;
ssize_t message_size = strlen(message);
while ( bytes_sent < message_size ){
ssize_t ret = write(server_socket, message+bytes_sent, message_size-bytes_sent);
if (ret==0){
print_connection_closed();
exit(1);
}
if (ret==-1 && (errno!=EINTR || errno!=EAGAIN)){
printf("write failed: sent %zd bytes out of %zd\n", bytes_sent, message_size);
exit(1);
}
if (ret!=-1){ bytes_sent+=ret; }
}
}
You can't use strlen() to determine the length of binary data. It'll miscount the data as soon as it sees a zero (NUL) byte in the binary encoding of the length field.
Write a more "primitive" function that takes the address of the data and its length as parameters, e.g.
void write_to_server_raw(const void *message, size_t message_size) {
...
}
If you still need the ability to send NUL terminated strings you can then rewrite your existing write_to_server() function so that it calls the new function to do the real work.
void write_to_server_string(const char *message) {
size_t message_size = strlen(message);
write_to_server_raw(message, message_size);
}

C: tcp recv not clearing old data

I have the following code in server.c
while (1) {
char msg[1024];
recv(fd, msg, 1024, 0);
}
From client, first, I sent "hello world".
And then I received "hello world" in server.
I then sent "hexx" to server.
But I received "hexxo world" on server.
It seems as if msg wasn't cleared fully.
Please let me know what I'm doing wrong.
Cheers.
You are allocating 1024 bytes for message and never zeroing that data. You are just reading into the same buffer over and over. First pass it reads "hello world" in the second pass you are putting "hexx" in the same starting address resulting in "hexxo world"
As DoxyLover mentions you can null terminate the newly read string and get what you are looking for.
tcp recv not clearing old data
Who said it would? Not that it should be necessary. You're ignoring the count returned by recv(). After calling recv(), there are three possibilities:
Return value of -1: an error; call perror().
Return value of 0: end of stream: close the socket and exit the read loop.
Return value is positive: you have received exactly that many bytes into your buffer, and you should not assume that any data beyond that count is valid.
At present you're doing none of these things correctly.
read() does not null terminate the buffer. Therefore, you are seeing the old data left over in the buffer.
What you want is something like:
while (1) {
char msg[1024];
ssize_t n = recv(fd, msg, 1023, 0);
if (n >= 0)
msg[n] = '\0';
}
Note that I am limiting the read to one less than the size of the buffer to allow space for the null byte. Obviously, this only works with text data. With binary data, you need to record the return value from read() and use that as a byte count when processing the buffer. For example, to copy data from one socket to another:
while (1) {
char msg[1024];
ssize_t n = recv(fd, msg, 1024, 0);
if (n > 0)
send(second_fd, msg, n, 0);
}
All of this is very simplified - you need error checking, check the return from read() to make sure any bytes were received, check the return from send() to make sure all of the byte were sent, etc.

some EOF mechanism for send(),recv() in C

I wonder, If i do 4 send() with my client, written in C, will my server need to read() 4 times, or could it be that the first read will read all 4 send()'s all together?
To help you out a little, you've basically answered your own question already.
You need to do it 'in tiers', so to speak.
Client:
int len = strlen(Filename) + 1; //Mind the terminating 0.
send(sock, (const char *)&len, sizeof(int), 0);
send(sock, Filename, len, 0); //Sending the filename
send(sock, &FileSize, sizeof(int), 0);
send(sock, FileBuf, FileSize, 0);
This code will send the entire data on the way (assuming that the entire file is in the 'FileBuf'-Variable).
Server:
int len;
char *FileBuf, FileName[20];
recv(sock, &len, sizeof(int), 0); //Receives the filename length. (4 Bytes)
recv(sock, FileName, len, 0); //Receives the filename (x bytes)
recv(sock, &len, sizeof(int), 0); //Receives the file length (again, 4 bytes)
FileBuf = new char[len]; //Creates sufficient space in memory.
recv(sock, FileBuf, len, 0); //Receives the file into the appropriate variable.
This is the absolute barebones variant, not very solid, but you should get the idea.
A more robust approach requires you to check the return values of recv() and send(). Both will return the amount of bytes, which have been processed with this call. If this amount equals '0', it means that the connection has been closed by the other end. (Mainly for recv()). If it equals -1, it means that something went wrong and you should check the errno variable.
If all goes well, it equals the exact amount of bytes you sent/tried to receive.
However in case it isn't 'len' (or 0 or -1), you could write a little wrapper like this.
unsigned char Recv(int sock, void *target, int Len) {
unsigned char *ptr = (unsigned char *)target, Ret = 0;
int RecvBytes = 1;
while(Len && !Ret) {
RecvBytes = recv(sock, ptr, Len, 0);
if(!RecvBytes) Ret = 1;
else if(RecvBytes == -1) Ret = errno;
else {
Len -= RecvBytes;
ptr += RecvBytes;
}
}
return Ret;
}
What this code does: It keeps receiving, until you either have received all the data you were expecting (the Len parameter) or an error occurred. If all goes well, it returns '0', which you can check with if(!Recv()).
Another useful wrapper function (a shortcut, so to speak) is this one:
uint32_t RecvInt(int sock) {
uint32_t Ret;
Recv(sock, &Ret, sizeof(Ret));
return ntohl(Ret);
}
This function receives exactly one unsigned int and corrects the endianess from network byte order to host byte order. (Network byte order is always big endian, host byte order is often: Little endian)
Using these wrapper functions, the code may be changed like this:
uint32_t len;
char *FileBuf, FileName[20];
len = RecvInt(sock); //Receives the filename length. (4 Bytes)
Recv(sock, FileName, len); //Receives the filename (x bytes)
len = RecvInt(sock); //Receives the file length (again, 4 bytes)
FileBuf = new char[len]; //Creates sufficient space in memory.
Recv(sock, FileBuf, len); //Receives the file into the appropriate variable.
For stream sockets (e.g. TCP): it makes no difference how many send() or write() calls were made on the sending end. The data could be returned in as few as one chunk, as many as n chunks of 1 byte each (where n is the number of bytes that were sent), or anything in between.
For datagram sockets (e.g. UDP): each recv() or recvmsg() call will return one complete datagram that was sent from the other end. The number of recv() or recvmsg() calls should be the same as the number of datagrams that were sent. recv() is preferred when reading from datagram sockets, but I believe read() should behave the same.
The number of write()s and read() need not be the same - it's possible that the write() writes all the data in one piece but on the other computer read() only manages to receive it in several chunks, and vice versa. That's why you should always check the return value of these functions and if only partial data transfer occurred, then continue with sending/receiving the rest.

write() and send() solving errors => difference?

could be any difference in solving errors between this two functions?:
To this question brought me another question ... is number of characters always same as number of bytes?
For more info: I use it in C on Linux for TCP socket comunication(sys/socket.h)
Thanks for your responses.
send()
write()
Return:
write():
On success, the number of bytes written are returned (zero indicates nothing was written). On error, -1 is returned, and errno is set appropriately. If count is zero and the file descriptor refers to a regular file, 0 will be returned without causing any other effect. For a special file, the results are not portable.
send():
The calls return the number of characters sent, or -1 if an error occurred.
Question from stackoverflow which says that this methods should be same with using flag zero.
here
int client_sockfd;
char* msg;
int length = strlen(msg);
//first option
if(send(client_sockfd, msg, length, 0) != length) return 1;
else return 0;
//second option
if(write(client_sockfd, msg, length) != length) return 1;
else return 0;
They will both return the same number of written bytes (== characters in this case. EXCEPT note this:
If the message is too long to pass atomically through the underlying protocol, the
error EMSGSIZE is returned, and the message is not transmitted.
In other words, depending on the size of the data being written, write() may succeed where send() may fail.
Number of bytes == number of characters, since the C standard reuires that char be an 1-byte integer.
write():
Yes, it returns the number of bytes written. But: it's not always an error if it doesn't return as many bytes as it should heva written. Especially not for TCP communication. A socket may be nonblocking or simply busy, in which case you'll need to rewrite the not-yet-written bytes. This behavior can be achieved like this:
char *buf = (however you acquire your byte buffer);
ssize_t len = (total number of bytes to be written out);
while (len > 0)
{
ssize_t written = write(sockfd, buf, len);
if (written < 0)
{
/* now THAT is an error */
break;
}
len -= written;
buf += written; /* tricky pointer arythmetic */
}
read():
Same applies here, with the only difference that EOF is indicated by returning 0, and it's not an error. Again, you have to retry reading if you want to receive all the available data from a socket.
int readbytes = 0;
char buf[512];
do {
readbytes = read(sockfd, buf, 512);
if (readbytes < 0)
{
/* error */
break;
}
if (readbytes > 0)
{
/* process your freshly read data chunk */
}
} while (readbytes > 0); /* until EOF */
You can see my implementation of a simple TCP helper class using this technique at https://github.com/H2CO3/TCPHelper/blob/master/TCPHelper.m

How would I go about sending bit-fields through a socket?

I need to send a set of bit fields along with a string of characters from a client to a server.
So given I have:
#define YES 1
#define FLAG 2
int main(int argc, char* argv[])
{
return sendToServer("The Message", YES | FLAG);
}
int sendToServer(char* msg, int bitfields)
{
/* create socket and connect to server */
/* Assume sock is set */
send(sock, msg, strlen(msg), 0);
return 0;
}
What would be the best way to send the bitfields? Is there anyway to send the bitfields along with the string?
EDIT: Ok I'm trying to implement Vlad's method. My client is pretty much identical to what he wrote. I have put the flag at the beginning data[0] and I used htonl instead of bswap. My server:
int main(int argc, char* argv[])
{
/* create socket and wait for connection */
char buffer[BUFFERSIZE];
size_t rcvdB = recv(clntSock, buffer, sizeof(int),0);
int flags = ntohl((int) buffer);
rcvdB = recv(clntSock, buffer, sizeof(size_t),0);
size_t msgSize = ntohl((size_t) buffer);
rcvdB = recv(clntSock,buffer,msgSize,0);
/* Then I send back to the client */
ssize_t sntB = send(clntSock,buffer,msgSize,0);
}
When the client prints the message there are multiple ascii characters at the end of the message.
EDIT2:
The issue seems to occur when I read more than 8 bytes of data
As others have pointed out, it depends on a protocol. I'd use something like this:
int sendToServer(char* msg, int bitfields)
{
unsigned int bits = bswap32 (bitfields); // Convert host to network byte order.
size_t len = strlen (msg); // Calculate string length.
size_t nlen = bswap64 (len); // Convert length's byte order from host to network.
iovec data[3]; // Prepare 3 I/O buffers to send data by performing a single system call (they are expensive).
// Send length of the string first.
data[0].iov_base = &nlen;
data[0].iov_len = sizeof (nlen);
// Send string...
data[1].iov_base = msg;
data[1].iov_len = len;
// And, of course, send bits.
data[2].iov_base = &bits;
data[2].iov_len = sizeof (bits);
// Write all of those to the socket.
writev (fd, &data, sizeof (data) / sizeof (data[0]));
}
On the receiving side, you can read the first sizeof (size_t) bytes, convert from network to host byte order, cast to size_t. That will tell you length of string. Then read buffer of that length - that will be your string. Finally, read another sizeof (int) bytes - that will be your bitfield.
See also:
Endianess
writev
This depends on your network protocol, of course. If you're designing it, and you have a maximum of 8 flags to send, put them in the first byte of the message. If you have at most 16, but them in the first two bytes, etc.
int sendToServer(int sock, char* msg, int flags)
{
size_t siz = strlen(msg) + 1; // +1 for NUL
unsigned char *buf = malloc_or_die(siz + 1);
buf[0] = flags;
memcpy(buf + 1, msg, size);
send(sock, msg, strlen(msg), 0);
free(buf);
return 0;
}
(I changed bitfields to flags since that's what they are. A bitfield is a collection of flags.)
It's probably best to send the bitfields as the bytes for a raw int (e.g., send(sock, &bitfields, sizeof(bitfields), 0)), making sure that the size & endianness is the same for both the client & server. It'd probably be easiest to send the bits before the string, as the server could then easily extract the string after a fixed number of bytes.
The bitfield forms a number, for instance 1|2 gives 3 since %01 | %10 = %11.
So all you have to send is that number. Kind of
snprintf(buffer, buffer_size, "%s-%d", message, number);
send(sockfd, buffer, buffer_size, 0);

Resources