read() from UDP socket drops data and blocks unexpectedly in C - c

I'm trying to read data from a UDP socket, but after reading the first 255 bytes, read() seems to drop the rest of the data on the socket and block until another data-gram comes in.
Here's the network code I'm using:
int sock;
struct sockaddr_in remote_addr, self_addr;
uint8_t network_init(uint16_t port)
{
memset((char *) &remote_addr, 0, sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr("192.168.1.22");
remote_addr.sin_port = htons(3001);
memset((char *) &self_addr, 0, sizeof(self_addr));
self_addr.sin_family = AF_INET;
self_addr.sin_addr.s_addr = INADDR_ANY;
self_addr.sin_port = htons(3001);
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
fprintf(stderr, "Could not create socket.");
return 1;
}
else if (bind(sock, (struct sockaddr *) &self_addr, sizeof(self_addr)) != 0)
{
fprintf(stderr, "Could not bind to socket.");
return 1;
}
return 0;
}
void network_send(uint8_t *data, uint8_t len)
{
sendto(sock, data, len, 0, (struct sockaddr *) &remote_addr, sizeof(remote_addr));
}
void read_data()
{
int len = 0;
ioctl(sock, FIONREAD, &len);
// We have data
if (len > 0)
{
char *buffer = (char *) malloc(256);
uint8_t buflen;
printf("==== %d | Data:\n", len);
while (len > 0)
{
buflen = min(255, len);
len = len - buflen;
buffer[buflen] = '\0';
printf("len: %d, buflen: %d,\n",len, buflen);
read(sock, buffer, buflen);
printf("%s\n", buffer);
}
printf("\n");
}
}
Here's the command I'm using to send data:
echo -n '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567' | nc -u localhost 3001
And here's the output:
==== 257 | Data:
len: 2, buflen: 255,
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345
len: 0, buflen: 2,
^C
Also, after performing this read, ioctl(sock, FIONREAD, &len); produces a length result of 0. My suspicion is that for some reason, read() is clearing out the rest of the data before it has a chance to be read, but I can't seem to find any reference to this behaviour in any documentation.
I'm developing on an Ubuntu linux machine (x86_64).

With UDP sockets, each call to read() reads a whole datagram out of the kernel. If the read buffer isn't big enough for the entire datagram, the rest of it will be discarded. It's not like a stream socket, where you can keep calling until you get everything.
Since FIONREAD tells you the number of bytes in the message, you should use that as the size to malloc() rather than using 256:
if (len > 0) {
char *buffer = malloc(len);
...
P.S. Do I cast the result of malloc?

Related

Recvfrom() keeps returning wrong value

I call udpclient in main where i pass "this is a test" as the parameter message.
#define MAX_BUFFER 128
void udpclient(char *message, char *target_ip, int target_port){
///* address of server we trying to reach */
struct sockaddr_in targetaddress;
/* buffer to receive echo */
char buffer[MAX_BUFFER];
/* create socket */
int socketfd;
socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if(socketfd == -1)
socketerror();
/* target server informations */
memset(&targetaddress, 0, sizeof(targetaddress));
targetaddress.sin_family = AF_INET;
targetaddress.sin_port = htons(target_port);
targetaddress.sin_addr.s_addr = inet_addr(target_ip);
After i send message to server, the server must reply "echo: this is a test", but recvfrom() for some reason is returning n = 8, so when i do write(1, buffer, n) it truncates buffer.
/* send message to targetaddress */
ssize_t n;
n = sendto(socketfd, message, sizeof(message), 0, (const struct sockaddr *) &targetaddress, sizeof(targetaddress));
if(n == -1)
udpsenderror();
printf("%i\n", n);
socklen_t addrlen;
addrlen = sizeof(targetaddress);
/* receive echo from targetaddress */
n = recvfrom(socketfd, buffer, MAX_BUFFER, 0, (struct sockaddr *) &targetaddress, &addrlen);
if(n == -1)
udpechoerror();
printf("%i\n", n);
write(1, "echo: ", 6);
write(1, buffer, n);
return;
}
Recvfrom() should be returning the lenght of message if i'm not mistaken, I don't know where i'm doing wrong! Help!?
n = sendto(socketfd, message, sizeof(message), 0, (const struct sockaddr *) &targetaddress, sizeof(targetaddress));
Since message is a char *, sizeof(message) gives the number of bytes a char * takes on your platform. Apparently, that's 8 bytes, so you sent an 8-byte message.

UDP socket: server sending file to client Address family not supported by protocol family

I am just a beginner in socket programming and currently working on an small program dealing with file transfer using UDP. This program is written in C.
Here is my problem:
UDP server will first use the recvfrom() function to catch message from UDP client so to start sending a file. I sent the file name first, and it couldn't went through, appearing with: Address family not supported by protocol family as the error message(). I checked the sin_family of client_addr, and it is 7. Furthermore, after I tried to set client_addr.sin_family = AF_INET; the server worked fine, except that the client couldn't even receive any message.
I have checked some sources but it happened to be not so helpful, please if anyone knows why and willing to tell. Appreciate all your help.
Below is a short portion of server code:
int socketfd;
/* my address information */
struct sockaddr_in server_addr;
/* connector’s address information */
struct sockaddr_in client_addr;
socklen_t clientLength;
int numbytes;
char buffer[BUFLEN];
int portNum = atoi(port);
time_t timer;
char charfileSize[20];
int percent, count = 0;
struct tm *tm_info;
char timeBuf[30];
if((socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("Server-socket() sockfd error lol!");
exit(1);
} else {
printf("Server-socket() sockfd is OK...\n");
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portNum);
server_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(server_addr.sin_zero), 0, 8);
// bind the socket to the server ip address
if(bind(socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
perror("server socket bind to IP error lol!\n");
exit(1);
} else {
printf("successfully bind server ip with socket ...\n");
}
// client_addr.sin_port = htons(portNum);
client_addr.sin_family = AF_INET;
//* for ensuring client connection *//
int tempGet;
char tempBuf[BUFLEN];
//if( (tempGet = recvfrom(socketfd, tempBuf, BUFLEN, 0, (struct sockaddr *)&client_addr, &clientLength)) > 0 ) {
tempGet = recvfrom(socketfd, tempBuf, BUFLEN, 0, (struct sockaddr *)&client_addr, &clientLength);
if( strcmp( tempBuf, "send file" ) == 0) {
printf("Can start transferring file...\n");
}
printf("sin family:%d\n", client_addr.sin_family);
FILE *fp = fopen(filename, "rb");
if ( !fp ) {
perror("Error opening the file\n");
exit(1);
} else {
// successfully opened the file that's going to be transferred
printf("file opened: %s\n", filename);
// get file size
int file_block_size = 0;
bzero(buffer, BUFLEN);
long file_size;
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
// goes back to the beginning of file(fp)
rewind(fp);
printf("file name: %s\n", filename);
printf("file size: %ld kb\n", file_size/1024);
// get time
time(&timer);
clientLength = sizeof(client_addr);
//client_addr.sin_family = AF_INET;
int sendFileName;
// length of file name
if( (sendFileName = sendto(socketfd, filename, strlen(filename), 0, (struct sockaddr *)&client_addr, sizeof(struct sockaddr_in))) >= 0) {
printf("file name sent.\n");
} else {
//printf("%d\n", sendFileName);
perror("file name send error.\n");
exit(1);
}
}
The last argument to recvfrom takes the address of a socklen_t which needs to be initialized with the size of the sockaddr parameter. I don't see clientLength initialized prior to this call, so client_addr is probably not being updated properly when this function returns. This causes the subsequent call to sendto to fail.
If you initialize clientLength before calling recvfrom that will take care of the problem.
clientLength = sizeof(client_addr);
tempGet = recvfrom(socketfd, tempBuf, BUFLEN, 0, (struct sockaddr *)&client_addr, &clientLength);
I am slightly tired of all incorrect and half-correct UDP socket program attempts at Stack Overflow. I have decided to do the reference UDP implementation, taking this question as an example. Next time I see TCP question (and have some time and energy) I will do reference TCP implementation.
This implementation does everything correctly (to the best of my knowledge :). It uses BSD sockets, so Windows implementations will have to make minor changes. Other than that, it should be C-99 conforiming in all.
Errors handling: application checks for possible errors, but does not try to correct them, simply reports. It also is known to leak a socket in certain error conditions (which lead to application shutdown), but adding proper socket close in this case will simply warrant for more code without actually adding a lot of benefit.
Compilation:
gcc -std=c99 -g -D_POSIX_SOURCE -Wall -Werror -pedantic -o test_udp send_udp.c
Usage: ./test_udp server or ./test_udp <hostname> <filename>
Behold: I give you test_udp.c.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
const short port = 4321;
int run_server();
int send_file(const char* const server, const char* const file);
int main(int argc, char* argv[]) {
if (argc < 2 || argc > 3) {
printf("Error: Usage send_udp (server|<server_host>) [<file name>]\n");
return 1;
}
if (!strcmp(argv[1], "server"))
return run_server(); // runs forever
if (argc != 3) {
printf("Error: client mode accepts two arguments: server and file name.\n");
return 1;
}
return send_file(argv[1], argv[2]);
}
int run_server() {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
printf("run_server(): error creating socket: %s\n", strerror(errno));
return 2;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr))) {
printf("run_server(): error binding socket: %s\n", strerror(errno));
return 2;
}
printf("run_server(): socket created and bound, entering endless loop.\n");
struct sockaddr_in incoming;
socklen_t incoming_sz = sizeof(incoming);
char buff[USHRT_MAX]; // maximum size of UDP datagramm
const char* buff_ptr = buff;
while (1) {
ssize_t msg_size = recvfrom(sock, buff, sizeof(buff), 0, (struct sockaddr*)(&incoming), &incoming_sz);
if (msg_size == -1) {
printf("run_server(): error receiving message: %s\n", strerror(errno));
return 3;
}
if (msg_size == 0) {
printf("run_server(): a message of 0 size received from the client, bogus. Skipping, continue to listen.\n");
continue;
}
// Message structure: unsigned 16 bit length of file name (network order), followed by filename, followed by data
uint16_t fname_len;
if (msg_size < sizeof(fname_len)) {
printf("run_server(): Bogus (too short) message received from the client. Skipping, continue to listen.\n");
continue;
}
memcpy(&fname_len, buff_ptr, sizeof(fname_len));
fname_len = ntohs(fname_len);
buff_ptr += sizeof(fname_len);
msg_size -= sizeof(fname_len);
if (msg_size < fname_len) {
printf("run_server(): Bogus (too short) message received from the client. Skipping, continue to listen.\n");
continue;
}
char file_name[fname_len + 1];
strncpy(file_name, buff_ptr, fname_len);
file_name[fname_len] = '\0';
buff_ptr += fname_len;
msg_size -= fname_len;
printf("run_server(): incoming transfer for file %s, intrinsic file size: %zu\n", file_name, msg_size);
FILE* f = fopen(file_name, "wb");
if (!f) {
printf("run_server(): Could not open file for writing. Skipping the message, carrying on.\n");
continue;
}
size_t written = fwrite(buff_ptr, msg_size, 1, f);
if (written != 1)
printf("run_server(): error, could not write whole file.\n");
else
printf("run_server(): incoming file written successfully.\n");
fclose(f);
}
return 0;
}
int send_file(const char* const server, const char* const file) {
uint16_t fname_len = strlen(file);
uint16_t max_short = 0;
max_short = ~max_short;
if (fname_len > (max_short - sizeof(fname_len))) {
printf("send_file(): file name is toooo large. Can't send this file.\n");
return 2;
}
FILE* f = fopen(file, "rb");
if (!f) {
printf("send_file(): Could not open file for reading. Nothing sent.\n");
return 3;
}
fseek(f, 0, SEEK_END);
unsigned long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fsize > max_short - sizeof(fname_len) - fname_len) {
printf("send_file(): file is toooo large. Can't send this file.\n");
fclose(f);
return 2;
}
char buff[sizeof(fname_len) + fname_len + fsize];
char* buff_ptr = buff;
uint16_t net_fname_len = htons(fname_len);
memcpy(buff_ptr, &net_fname_len, sizeof(net_fname_len));
buff_ptr += sizeof(net_fname_len);
memcpy(buff_ptr, file, fname_len);
buff_ptr += fname_len;
size_t rc = fread(buff_ptr, fsize, 1, f);
if (rc != 1) {
printf("send_file(): Could not read whole file. Error.\n");
fclose(f);
return 3;
}
fclose(f);
struct addrinfo* ainfo;
if (getaddrinfo(server, NULL, NULL, &ainfo) != 0) {
printf("send_file(): Unknown host %s.\n", server);
return 3;
}
struct addrinfo* ainfo_begin = ainfo;
// I will take the first IP v4 entry in possible addressess
while (ainfo->ai_family != AF_INET && ainfo->ai_next)
ainfo = ainfo->ai_next;
if (ainfo->ai_family != AF_INET) {
printf("send_file(): Couldn't resolve host %s to AF_INET address.\n", server);
return 3;
}
int addr = ((struct sockaddr_in*)(ainfo->ai_addr))->sin_addr.s_addr;
freeaddrinfo(ainfo_begin);
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
printf("read_file(): error creating socket: %s\n", strerror(errno));
return 2;
}
struct sockaddr_in remote_addr;
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(port);
remote_addr.sin_addr.s_addr = addr;
ssize_t sent = sendto(sock, buff, sizeof(buff), 0, (struct sockaddr*)(&remote_addr), sizeof(remote_addr));
if (sent != sizeof(buff))
printf("read_file(): error sending message over socket: %s, only %zu bytes sent.\n", strerror(errno), sent);
else
printf("read_file(): file sent successfully.\n");
return sent == sizeof(buff) ? 0 : 3;
}

Using 'abstract sockets' with AF_UNIX SOCK_DGRAM

I am trying to modify the original Michael Kerrisk's AF_UNIX SOCK_DGRAM sample client/server program. Please click on the following two links (client, server) for more info. The example code was originally published in his book The Linux Programming Interface, chapter 57. My goal is to replace the 'file socket' definition with 'abstract socket' definition, based on Kerrisk's code example.
Unfortunately, I am not able to establish communication between my version of the client and server. Of course, Kerrisk's version works with a flying colors.
It is obvious to me, that I am doing something fundamentally wrong... but... I could not figured out what it is.
=================== SERVER ===============================
Here is my version of the Kerrisk's code for 'server':
int main(int argc, char *argv[])
{
struct sockaddr_un svaddr, claddr;
int sfd, j;
ssize_t numBytes;
socklen_t len;
char buf[BUF_SIZE];
char *abstract_server;
sfd = socket(AF_UNIX, SOCK_DGRAM, 0); /* Create server socket */
if (sfd == -1)
errExit("socket");
abstract_server = "viper_server";
/* Construct well-known address and bind server socket to it */
if (remove(abstract_server) == -1 && errno != ENOENT)
errExit("remove-%s", abstract_server);
memset(&svaddr, 0, sizeof(struct sockaddr_un));
svaddr.sun_family = AF_UNIX;
strncpy(&svaddr.sun_path[1], abstract_server, strlen(abstract_server));
if (bind(sfd, (struct sockaddr *) &svaddr,
sizeof(sa_family_t) + strlen(abstract_server) + 1) == -1)
errExit("bind");
/* Receive messages, convert to uppercase, and return to client */
for (;;) {
len = sizeof(struct sockaddr_un);
numBytes = recvfrom(sfd, buf, BUF_SIZE, 0,
(struct sockaddr *) &claddr, &len);
if (numBytes == -1)
errExit("recvfrom");
printf("Server received %ld bytes from %s\n", (long) numBytes,
claddr.sun_path);
for (j = 0; j < numBytes; j++)
buf[j] = toupper((unsigned char) buf[j]);
if (sendto(sfd, buf, numBytes, 0, (struct sockaddr *) &claddr, len) != numBytes)
fatal("sendto");
}
}
========================= CLIENT ============================
This is my version of the Kerrisk's code for the 'client':
int main(int argc, char *argv[])
{
struct sockaddr_un svaddr, claddr;
int sfd, j;
size_t msgLen;
ssize_t numBytes;
char resp[BUF_SIZE];
char *abstract_client;
char *abstract_server;
if (argc < 2 || strcmp(argv[1], "--help") == 0)
usageErr("%s msg...\n", argv[0]);
/* Create client socket; bind to unique pathname (based on PID) */
sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sfd == -1)
errExit("socket");
abstract_client = "viper_client";
abstract_server = "viper_server";
memset(&claddr, 0, sizeof(struct sockaddr_un));
claddr.sun_family = AF_UNIX;
strncpy(&claddr.sun_path[1], abstract_client, strlen(abstract_client));
if (bind(sfd, (struct sockaddr *) &claddr,
sizeof(sa_family_t) + strlen(abstract_client) + 1) == -1)
errExit("bind");
/* Construct address of server */
memset(&svaddr, 0, sizeof(struct sockaddr_un));
svaddr.sun_family = AF_UNIX;
strncpy(&svaddr.sun_path[1], abstract_server, strlen(abstract_server));
/* Send messages to server; echo responses on stdout */
for (j = 1; j < argc; j++) {
msgLen = strlen(argv[j]); /* May be longer than BUF_SIZE */
/* code FIX */
if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
(sizeof(sa_family_t) + strlen(abstract_server) + 1) ) != msgLen)
fatal("sendto");
/* original - non working code - replaced with the code FIX above
if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
sizeof(struct sockaddr_un)) != msgLen)
{
fatal("sendto");
} */
numBytes = recvfrom(sfd, resp, BUF_SIZE, 0, NULL, NULL);
/* Or equivalently: numBytes = recv(sfd, resp, BUF_SIZE, 0);
or: numBytes = read(sfd, resp, BUF_SIZE); */
if (numBytes == -1)
errExit("recvfrom");
printf("Response %d: %.*s\n", j, (int) numBytes, resp);
}
remove(claddr.sun_path); /* Remove client socket pathname */
exit(EXIT_SUCCESS);
}
How I am launching the test:
> ./server &
> ./client aa bb cc
> result: ERROR: sendto
Any help | suggestion | solution | RTFM is very welcome
Igor
P.S. Since my reputation is less than 10, I can post ONLY 2 links (see Kerrisk's client URL, Kerrrisk's server URL at the top of this post). So, I did a "cut&paste" the Kerrisk's C-code snippet for "How to use abstract sockets". It was published in his book on page 1176, Listing 57-8.
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_un addr;
char *str;
memset(&addr, 0, sizeof(struct sockaddr_un)); /* Clear address structure */
addr.sun_family = AF_UNIX; /* UNIX domain address */
/* addr.sun_path[0] has already been set to 0 by memset() */
str = "xyz"; /* Abstract name is "\0abc" */
strncpy(&addr.sun_path[1], str, strlen(str));
// In early printings of the book, the above two lines were instead:
//
// strncpy(&addr.sun_path[1], "xyz", sizeof(addr.sun_path) - 2);
// /* Abstract name is "xyz" followed by null bytes */
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1)
errExit("socket");
if (bind(sockfd, (struct sockaddr *) &addr,
sizeof(sa_family_t) + strlen(str) + 1) == -1)
errExit("bind");
// In early printings of the book, the final part of the bind() call
// above was instead:
// sizeof(struct sockaddr_un)) == -1)
sleep(60);
exit(EXIT_SUCCESS);
}
if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
sizeof(struct sockaddr_un)) != msgLen)
The last arg is invalid, the sockaddr_un address length should be
sizeof(sa_family_t) + strlen(abstract_client) + 1;
BTW, you should print out the "errno" value to precisely locate what happened when errorly returned from the glibc API. In the above case, the "errno" value is "111", indicating the server address cannot be reached.
OK, After having read your post once more, I think I got what you mean.
When you use the no abstract unix sockets(sun_path[0] != 0), the server name len is calculated by using strlen(sun_path) in the kernel. So the last arg is not really used.
net/unix/af_unix.c:unix_mkname
if (sunaddr->sun_path[0]) {
/* ... */
((char *)sunaddr)[len] = 0;
len = strlen(sunaddr->sun_path)+1+sizeof(short);
return len;
}
But when you use the abstract unix sockets(sun_path[0] == 0), the server name len is the last arg that your "bind" or "sendto".
net/unix/af_unix.c:unix_mkname:
*hashp = unix_hash_fold(csum_partial(sunaddr, len, 0));
So when you bind the socket to the address with length,
if (bind(sfd, (struct sockaddr *) &svaddr,
sizeof(sa_family_t) + strlen(abstract_server) + 1) == -1)
Kernel think the server name is an array with that length.
When you try to send to an address with
if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
sizeof((struct sockaddr)) != msgLen)
Kernel think the server name is an array with that length of the last arg.
Because,
sizeof((struct sockaddr)) != sizeof(sa_family_t) + strlen(abstract_server) + 1
Kernel will not think the address is the same, so sendto returns with errno 111.
Your server binds to a different address than the client uses in sendto(). This is because you calculate the length of the svaddr differently in the client and server.
server:
sizeof(sa_family_t) + strlen(abstract_server) + 1)
client:
sizeof(struct sockaddr_un)
The unix socket address is the whole given length of the path described in struct sockaddr_un.sun_path. After changing the size calculations to match the client and server work.
EDIT s/abstract_client/abstract_server/ Seems I had the same copy&paste error as the other answer.

How to read the buffer from a paquet (tftp)

I am currently trying to write a tftp in C. But i have some difficulties to read the packet that I sent.
Here is what I have :
The struct that I am sending :
typedef struct {
short type;
short block_num;
char* data;
} data_t;
the function (server's side) wich send the packet :
if ( s = sendto (serverSocket, data, 512 ,0,
(struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0 )
{
perror("sendto");
exit(1);
}
For some reason s = 0, I am not sure it is correct.
Client's side :
char buffer[512 ];
if ( (n = recv(serverSocket, buffer, 512-1,0)) < 0 )
{
perror("recv");
exit(1);
}
data_t * data = malloc (1024);
data->data = malloc(512);
create_data(buffer,data)
and the create_data function :
int create_data( char * buffer, data_t* request)
{
data_t * tmp = (data_t*) buffer;
request->type = tmp->type;
request->block_num = tmp->block_num;
strcpy(request->data, tmp->data);
return 0;
}
Unfortunatly it does not work, it seems the issue comes from strcpy in create_data , but I don't know why.
here is the code for serverSocket creation (server's side)
memset( (char *) &serv_addr,0, sizeof(serv_addr) );
serv_addr.sin_family = PF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERV_PORT);
/*
* Ouvrir socket UDP
*/
if ((serverSocket = socket(PF_INET, SOCK_DGRAM, 0)) <0)
{
perror ("erreur socket");
exit (1);
}
ttl=1;
if (setsockopt(serverSocket, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) <0)
{
perror ("setsockopt");
exit (1);
}
if ( bind(serverSocket,(struct sockaddr *) & serv_addr, sizeof(serv_addr) ) < 0 )
{
perror("servecho: erreur bind\n");
exit(1);
}
request = malloc(sizeof(request_t));
....
sendto returns number of bytes sent, so if it is returning 0, no bytes have been sent.
In the server part of code, you seem to have a sendto with destination as server address ? (which has INETADDR_ANY as the address). This could be the reason for malfunction. The procedure should be to have the server do a recvfrom first (after bind) and then respond back with sendto, to same address received in recvfrom.
Here is a good example for Server and Client.
Received data or data to be sent is binary, you cannot use strcpy, strcpy will stop at the first null byte '\0', you need to use memcpy.
Good practice: While allocating memory data_t * data = malloc (1024);, I recommend you use malloc( sizeof(data_t));

maximum data that can be sent through a port-socket

i have implemented a program which takes input from client, performs operation on server and writes the data to the client. ls command is what i have chosen for example.
Now my doubt is,
1) what if the input is very huge in bytes??
2) what is the maximum data that can be sent through a socket port??
client.c
int main()
{
FILE *fp;
int servfd, clifd;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
int cliaddr_len;
char str[4096], clientip[16];
int n;
servfd = socket(AF_INET, SOCK_STREAM, 0);
if(servfd < 0)
{
perror("socket");
exit(5);
}
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERVPORT);
servaddr.sin_addr.s_addr = inet_addr(SERVIP);
if(bind(servfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind");
exit(0);
}
listen(servfd, 5);
printf("Server is waiting for client connection.....\n");
while(1)
{
cliaddr_len=sizeof(cliaddr);
clifd = accept(servfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
strcpy(clientip, inet_ntoa(cliaddr.sin_addr));
printf("Client connected: %s\n", clientip);
if(fork() == 0)
{
close(servfd);
while(1)
{
n = read(clifd, str, sizeof(str));
str[n] = 0;
if(strcmp(str, "end") == 0)
{
printf("\nclient(%s) is ending session and server is waiting for new connections\n\n", clientip);
break;
}
else if (strcmp(str, "ls") == 0) {
system("ls >> temp.txt");
fp = fopen("temp.txt", "r");
fread(str, 1, 500, fp);
remove("temp.txt");
}
else
printf("Received from client(%s): %s\n", clientip, str);
write(clifd, str, strlen(str));
}
close(clifd);
exit(0);
}
else
{
close(clifd);
}
}
}
server.c
int main()
{
int sockfd;
struct sockaddr_in servaddr;
char str[500];
int n;
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERVPORT);
servaddr.sin_addr.s_addr = inet_addr(SERVIP);
if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
printf("Could not connect to server: %s\n", strerror(errno));
exit(1);
}
while(1)
{
printf("Enter message: ");
scanf(" %[^\n]", str);
write(sockfd, str, strlen(str));
if(strcmp(str, "end") == 0)
break;
n = read(sockfd, str, sizeof(str));
str[n] = 0;
printf("Read from server: %s\n", str);
}
close(sockfd);
}
As for your question no 1. the huge data is broken in many packets & then sent packet by packet its done by OS internally. & the one packet size depends on your system OS(you can change it.It is called MTU maximum transfer unit).
& for your question no 2. the data send by a socket port may be infinite coz as long as u wish to send data it will send. there is no limit.!!!
Q: What if the input is very huge in bytes?? What is the maximum data that can be sent through a socket port??
A: There is no limit on the size of a TCP/IP stream. In theory, you could send and receive an infinite number of bytes.
... HOWEVER ...
1) The receiver must never assume is will ever get all the bytes at once, in a single read. You must always read socket data in a loop, reading as much at a time as you wish, and appending it to the data you've already read.
2) You can send a "large" amount of data at once, but the OS will buffer it behind your back.
3) Even then, there's an OS limit. For example, here the maximum send buffer size is 1 048 576 bytes.:
http://publib.boulder.ibm.com/infocenter/tpfhelp/current/index.jsp?topic=%2Fcom.ibm.ztpf-ztpfdf.doc_put.cur%2Fgtpc2%2Fcpp_send.html
If you need to send more, you must send() in a loop.
PS:
As Anish recommended, definitely check out Beej's Guide to Network programming:
http://beej.us/guide/bgnet/output/html/multipage/

Resources