I want to create a socket that can read some numbers rather than string so that I can perform some manipulations on them.
How can I send integer instead of string
This is my current program:
int main(int argc, char *argv[])
{
int sockfd, newsockfd, port, clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2)
error("ERROR, no port provided\n");
port = atoi(argv[1]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port); //host to network
if (bind(sockfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR binding to socket");
listen(sockfd,2);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,(struct sockaddr *)&cli_addr, &clilen);
int n;
void* buffer[256];
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Message received:%d\n",d);
n = write(newsockfd,buffer, strlen((char *)buffer));
if (n < 0)
error("ERROR writing back to socket");
return 0;}
I tried this:
int n= 5;
write(newsockfd,&n, sizeof(int));
But on the client side (also a void* buffer), it doesn't seem to read anything. Can anyone help me how can I rectify this?
One solution could be to pass strings then convert to int etc. But is that the proper way?
The problem is two-fold:
The first problem is that the declaration void* buffer[256] declares buffer to be an array of 256 pointers to void, not really what's intended I guess. Instead if you want an array of 256 bytes just do char buffer[256].
The second problem is that on the receiving side you treat the data as a string, but it's not a string it's a binary data value.
The second problem can be solved in two ways: Either you convert the integer to a string, and send that string. Or you receive the raw data of the integer, and convert it to an int. The first solution involves sprintf, and the other solution involves either memcpy or pointers and casting.
For the first solution above, you could do something like this:
char temp[32];
snprintf(temp, sizeof temp, "%d", n);
write(newsockfd, temp, sizeof temp);
On the receiving end you read it as a string:
char buffer[32];
n = read(newsockfd, buffer, sizeof buffer);
if (n <= 0)
{
// Error or connection closed
}
// TODO: Since TCP is a streaming protocol, we could actually receive
// less than the number of bytes we asked to read, so we need
// to read in a loop
// Print the received data as a string
printf("Received '%s'\n", buffer); // Works because the sender sent with the terminator
// Convert to integer
int i = strtol(buffer, NULL, 10);
printf("Received %d\n", i);
For the second solution above, send the integer value as raw binary data as you already do, but when receiving this do something like
char buffer[32];
n = read(newsockfd, buffer, sizeof buffer);
if (n <= 0)
{
// Error or connection closed
}
// TODO: Since TCP is a streaming protocol, we could actually receive
// less than the number of bytes we asked to read, so we need
// to read in a loop
int i = *(int *) buffer;
printf("Received %d\n", i);
Note that this second solution, as it is written in this answer, relies that both the sender and the receiver have the same endianness, as well as the same size for int (which might not always be the case).
The safest way is generally to convert to a string on the sending side, and receive the string as, well, a string. I.e. the first solution.
I'd like to modify the lucid answer Joachim Pileborg provided.
int value, todo = sizeof(value);
char *p = (void*) &value;
while ( (n = read(newsockfd, p, todo)) < todo ) {
if( n == 0 ) { /* handle eof and break */ }
if( n < 0 ) { /* handle error and break */ }
todo -= n;
p += n
}
if( todo == 0 ) {
printf("Received %d\n", value);
}
You know how many bytes you're receiving, so there's no reason to read more. The loop deals with case he warns of: that read(2) may fail to read all 4 bytes (unlikely in this case, but not in general).
You can always get char * from void *, and pass any pointer to a function accepting void *. What you cannot do, portably, is
char buffer[32];
...
int i = *(int *) buffer;
because a character array is not guaranteed to have integer alignment. On some architectures, that provokes SIGBUS. If you read into character array, the safe way to interpret those bytes as an integer is
memcpy(&i, buffer, sizeof i);
Related
I'm writing a code for my project in C. I need to add a loop so that the ip_address can be passed to inet_addr() from the array and I can print the send & receive the data. But my code is only executing till printf("Send \n") and I'm not receiving anything after that. The program seems to just hang up & I'm not getting any errors too. Also, the code is running fine when I'm hardcoding the address(eg."100.12.1.10") directly. I tried various methods but nothing seems to be working. I can't figure it out.
It would be great if you guys have any suggestions.
PS: This is only a part of the whole code and other parts are working fine.
unsigned char *ip_address[25] = { "879.120.8.249",
"232.106.122.6",
"17.105.176.86",
"85.195.823.169", ......}
for(int k = 0; k < 25; k++) {
size_t l = strlen(ip_address[k]);
char address[l];
//address = (char*)malloc(l);
memcpy(address, ip_address[k], l+1);
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_addr.s_addr = inet_addr(address);
//printf("Ip_address = %s\n", ip_address[k]);
//printf("address = %s\n", address);
int n, len=0;
for(i=0;i<MAXLINE;i++){
len++;
if(buffer[i]==62 && buffer[i-1]==62)
break;
}
printf("Len = %d\n", len);
printf("Send \n");
sendto(sockfd, (const char *)buffer, len,
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
printf("before Receive");
n = recvfrom(sockfd, (char *)recv_buffer, MAXLINE,
MSG_WAITALL, (struct sockaddr *) &servaddr,
&len);
printf("after receive");
for(i=0;i<n;i++){
printf("%d,", recv_buffer[i]);
}
printf("\n");
close(sockfd);
}
At least these problems:
Insufficient space
// char address[l]; // too small
char address[l+1];
memcpy(address, ip_address[k], l+1);
Index of -1?
buffer[] not defined, yet buffer[0-1] looks strange
for(i=0;i<MAXLINE;i++){
len++;
if(buffer[i]==62 && buffer[i-1]==62)
break;
}
Perhaps
//if(buffer[i]==62 && buffer[i-1]==62)
if(i > 0 && buffer[i]==62 && buffer[i-1]==62)
Well, I got it working today somehow.
unsigned char *ip_address[25] = { "879.120.8.249",
"232.106.122.6",
"17.105.176.86",
"85.195.823.169", ......};
Here, I changed the unsigned char to const char, then used the variable directly, and it worked somehow.
servaddr.sin_addr.s_addr = inet_addr(ip_address[k]);
I've got a simple client/server application. The user writes strings in the console. When he pushes enter string is sent. I can transfer one line correctly, but after it substitutes the first letter of first sent word to each next. For example, if a user sends "Hello", the server will get "Hello", but after, if I send "Hello" again, the server will get "HHello". If I try to clear buffer at the client-side after sending it, it never sends something again.
Server code:
// Server side C/C++ program to demonstrate Socket programming
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 57174
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
char buffer[1024];
bzero(buffer, sizeof(buffer));
int step = 0;
while(1){
valread = read( new_socket , buffer, 1024);
if(valread == 0)
break;
printf("%s", buffer );
printf("\n");
bzero(buffer, sizeof(buffer));
};
return 0;
}
Client code:
// Client side C/C++ program to demonstrate Socket programming
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define PORT 57174
int main(int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(atoi(argv[2]));
// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
// char buffer[1024] = {0};
unsigned int N = 10, delta=10, i = 0;
char* buf = (char*) malloc (sizeof(char)*N);
while (1) {
buf[i] = getchar();
if(buf[i] == 27)
break;
if(buf[i] == 10){
send(sock , buf , strlen(buf) , 0 );
// bzero(buf, sizeof(buf));
N = 10;
buf = (char*) realloc (buf, sizeof(char)*N);
i = 0;
}
if (++i >= N) {
N += delta;
buf = (char*) realloc (buf, sizeof(char)*N);
}
}
return 0;
}
if a user sends "Hello", the server will get "Hello", but after, if I send "Hello" again, the server will get "HHello"
This is because you missed an else in your client, in
if(buf[i] == 10){
send(sock , buf , strlen(buf) , 0 );
// bzero(buf, sizeof(buf));
N = 10;
buf = (char*) realloc (buf, sizeof(char)*N);
i = 0;
}
if (++i >= N) {
N += delta;
buf = (char*) realloc (buf, sizeof(char)*N);
}
you need to replace
if (++i >= N) {
by
else if (++i >= N) {
else after you sent you buffer and set i to 0 you increment it, and you will memorize the next char at the index 1, the character at the index 0 is still present and you will send it again and again
You also have a problem in your client at
send(sock , buf , strlen(buf) , 0 );
because you do not put a null character in buff needed by strlen to return the expected value, so the behavior is undefined. In fact you do not need strlen, just do
send(sock , buf , i , 0 );
supposing you do not want to send the \n
On your server side
char buffer[1024];
...
valread = read( new_socket , buffer, 1024);
if(valread == 0)
break;
printf("%s", buffer );
you fill each time buffer with null characters but in case you read 1024 characters there is no null character in your buffer and printf will go out of the buffer with an undefined behavior
warning read returns -1 on error, valread == 0 is wrong
remove all your bzero an just do
char buffer[1024];
...
while ((valread = read(new_socket, buffer, sizeof(buffer)-1)) > 0) {
buffer[valread ] = 0;
printf("%s", buffer);
}
notice I used sizeof(buffer) rather than 1024, that allows to be sure to have the right size even you resize buffer
Other remarks for the client :
the variable hello is useless
by definition sizeof(char) values 1, so sizeof(char)*N can be replaced by N everywhere
do not compare the read char with the literal 10 and 27, compare with '\n' and '\e'
you do not manage the EOF in input, for that you need to save the read char in an int rather than a char (like buf[i] is) to compare it with EOF
In the server the variable step is useless
Out of that you use SOCK_STREAM so your socket is a stream (tcp not udp), that means you cannot suppose the size of the data you read each time you call read, I mean if the client sent N bytes that does not mean the server will read N bytes on the corresponding read (if I can say 'corresponding' because there is no correspondence ;-) ).
Supposing the other problems are fixed if you input azeqsd\n you send azeqsd but may be on the server side you will read azeq so print azeq\n and on the next loop you will read sd and print sd\n.
It is also possible the server read a partial or full concatenation of several buffers sent separably by the client.
Do you want that behavior ? if no you need to send the size before each buffer to know how much to read even on several times to constitute the full sent buffer (an other advantage is you no not read byte per
I have a client and a server. I have two read() in my client and two write() in my server code. The server sends data to the client on the first write(), the client reads and stores to a buffer but it doesn't stop reading, it keeps reading through the server's second write() because in my client i have it set up to read 255 in the stream(from my understanding). I put 255 because i don't know how long the data datasize for first write() is. How do i fix this?
Client:
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
Server:
n = write(newsockfd,datasize,strlen(datasize));
if (n < 0) error("ERROR writing to socket");
n = write(newsockfd,data,255);
if (n < 0) error("ERROR writing to socket");
What you are experiencing is how TCP works. If the server calls write() multiple times before the client calls read(), then read() can receive everything that was previously written, up to the maximum buffer size that you specify. TCP has no concept of message boundaries, like UDP does. There is nothing wrong with that. You just need to account for it, that's all.
If you need to know where one message ends and the next begins, then you simply need to frame your messages. There are a couple of different ways you can do that.
Send the data length before sending the actual data, so the client knows how much data to read, eg:
Server:
int datalen = ...; // # of bytes in data
int tmp = htonl(datalen);
n = write(newsockfd, (char*)&tmp, sizeof(tmp));
if (n < 0) error("ERROR writing to socket");
n = write(newsockfd, data, datalen);
if (n < 0) error("ERROR writing to socket");
Client:
int buflen;
n = read(sockfd, (char*)&buflen, sizeof(buflen));
if (n < 0) error("ERROR reading from socket");
buflen = ntohl(buflen);
n = read(sockfd, buffer, buflen);
if (n < 0) error("ERROR reading from socket");
else printf("%*.*s\n", n, n, buffer);
wrap the data with delimiters that do not appear in the actual data, then the client can keep reading and look for those delimiters. Use whatever delimiters make sense for your data (STX/ETX, line breaks, special reserved characters, etc):
Server:
char delim = '\x2';
n = write(newsockfd, &delim, 1);
if (n < 0) error("ERROR writing to socket");
n = write(newsockfd, data, datalen);
if (n < 0) error("ERROR writing to socket");
delim = '\x3';
n = write(newsockfd, &delim, 1);
if (n < 0) error("ERROR writing to socket");
Client:
char tmp;
do
{
n = read(sockfd, &tmp, 1);
if (n < 0) error("ERROR reading from socket");
if (tmp != '\x2')
continue;
buflen = 0;
do
{
n = read(sockfd, &tmp, 1);
if (n < 0) error("ERROR reading from socket");
if (tmp == '\x3')
break;
// TODO: if the buffer's capacity has been reached, either reallocate the buffer with a larger size, or fail the operation...
buffer[buflen] = tmp;
++buflen;
}
while (1);
printf("%*.*s\n", buflen, buflen, buffer);
break;
}
while (1);
You can't assume that one read will read exactly what was written by one write. TCP is a byte stream protocol. No message boundaries. read() can read as little as one byte and as much as the length you provide, depending on what data has arrived, which you can't control at either the sending or the receiving end. You also can't control whether TCP coalesces outgoing writes into one segment.
If you want messages, you have to implement them yourself, e.g. lines, length-word prefix, type-length-value, STX/ETX, XML, ...
NB When you get an error, don't just print a message of your own devising. Print the error. In this case, call 'perror()', or make up a formatted string with 'strerror'.
You've got the right idea about sending the length data before sending the actual data, but you're sending datasize in the wrong format. Sending it as an ascii string means the length of datasize will vary depending on the length of data:
For instance:
If data is 5 bytes in length, datasize will be "5".
If data is 100 bytes in length, datasize will be "100".
Unfortunately when it comes to serializing data, this just won't work, datasize must always take up the same number of bytes. You need to write this into the socket as an integer, and read it again at the other end as an integer. Then write this exact number of bytes of data into the socket and read this exact number of bytes of data at the other end:
For example:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
void send(int sock)
{
const char* msg = "this is a message!";
uint16_t len = strlen(msg);
uint16_t networkLen = htons(len); // convert to network byte order
write(sock, &networkLen, sizeof(networkLen));
write(sock, msg, len);
}
void receive(int sock)
{
char msg[1024];
uint16_t networkLen;
read(sock, &networkLen, sizeof(networkLen));
uint16_t len = ntohs(networkLen); // convert back to host byte order
read(sock, msg, sizeof(msg) - 1);
msg[len] = '\0';
printf("%u %s\n", len, msg);
}
int main(int argc, char** argv)
{
int sockets[2];
pipe(sockets);
send(sockets[1]);
receive(sockets[0]);
}
Socket == stream of bytes, it doesn't make some packetizing etc. So if Server should send 2 packets to client, you need to do something so client can distinguish each of them. For instance, if you decide that server should send 2 packets by 255 bytes each, your client procedure which receives one packet would look like this:
int count = 0;
while (count < 255) {
n = read(sockfd, buffer + count, 255 - count);
if (n < 0) {
error("ERROR reading from socket");
printf("%s\n",buffer);
return;
}
count += n;
}
// here buffer has 255 bytes for the packet
The program has cycle, because you can receive any number in read result in between 0..255, or negative if the socket was closed.
you can do the same for second packet.
If your packets are different in size, then you have to tell client from server what the packet size is. You can send in first 2 bytes the length of your packet, and use the number instead of 255 constant in code above.
I wrote this program which listens on a given port and then, once a connection is received, outputs a single line of text and disconnects. It runs for days, processing thousands of queries, but then (inevitably) crashes and I have to go restart it. Wondering if anyone sees anything wrong with it, or (alternatively) if anyone can suggest a way to make it more robust.
int main(int argc, char *argv[])
{
srand(time(0));
int sockfd, newsockfd, portno;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1)
{
unsigned char write_val;
unsigned char y[BYTES];
int i, j;
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
fill_buffer(y); // fills buffer y with a 128-bit string; not included here
for (i=BYTES-1; i >= 0; i--)
{
const void* ZERO = (void *)"0";
const void* ONE = (void *)"1";
for (j=7; j >= 0; j--)
write(newsockfd, (y[i] >> j) & 1 ? ONE : ZERO, 1);
}
write(newsockfd, "\n", 1);
close(newsockfd);
}
close(sockfd);
return 0;
}
anyone sees anything wrong with it
While this code could be made more efficient (by writing all the bytes in one single pass for example), there's no obvious flaw there.
That makes the unpublished part of your code a decent candidate for the problem:
fill_buffer(y); // fills buffer y with a 128-bit string; not included here
If you read more bytes than y[]'s size then you will crash.
or (alternatively) if anyone can suggest a way to make it more robust
Try enlarging the size of this y[] buffer (doubling it can't hurt).
And make sure that fill_buffer() can't read more than BYTES characters.
Publish this missing code in case of doubt.
You could also compile your code with debug symbols and dump a backtrace (with symbols) in a file from your signal handler. This way, if your program crashes, you will know where and why.
The code looks good with some comments.
One somewhat important comment:
portno should be declared as unsigned short. This works OK with an Intel-like (little endian) processor but it won't be portable to a processor with different endianness.
Anyway it was not the reason for your process crashing.
Obviously the crash occurs while executing within the 'while', and by looking at the code, if it crashes for a buffer overflow, the only possibility is within fill_buffer.
If you show the definition of BYTES and fill_buffer it will be easier to help you.
Now, if it is not a buffer overflow, there is the possibility that it aborts in the write if the client closed the connection before the server writes into the socket. In that case the process will receive a signal SIGPIPE and it will abort if the code does not handle that signal.
You can also ignore SIGPIPE with:
signal(SIGPIPE, SIG_IGN);
Other possibility is if you are doing something weird with write_val and you're not showing that code.
I hope this helps.
Can any one please tell me how can we send integers from client to server and add them
in c.
I was able to send strings successfully but i am not able to figure out how to send
integers.
Please help me out!! The below written code was for reading strings. How can i change it
it to read and add integers.
#define SOCK_PATH "echo_socket"
int main(void)
{
int s, t, len;
struct sockaddr_un remote;
char str[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
printf("Trying to connect...\n");
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCK_PATH);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
int val=connect(s, (struct sockaddr *)&remote, len);
if ( val< 0) {
perror("connect");
exit(1);
}
printf("Connected.\n");
printf("ENTER THE NUMBERS:");
while(printf("> "), fgets(str, 100, stdin), !feof(stdin)) {
if (send(s, str, strlen(str), 0) == -1) {
perror("send");
exit(1);
}
if ((t=recv(s, str, 100, 0)) > 0) {
str[t] = '\0';
printf("echo> %s", str);
} else
{
if (t < 0) perror("recv");
else printf("Server closed connection\n");
exit(1);
}
}
Simple:
int my_int = 1234;
send(socket, &my_int, sizeof(my_int), 0);
The above code sends the integer as is over the socket. To receive it on the other side:
int my_int;
recv(socket, &my_int, sizeof(my_int), 0);
However, be careful if the two programs runs on systems with different byte order.
Edit: If you worry about platform compatibilities, byte ordering and such, then converting all data to strings on one end and then convert it back on the other, might be the best choice. See e.g. the answer from cnicutar.
You can use sprintf to turn them into strings and then strtoul to turn them back into integers. Or you can just memcpy integers to and from a char array.