Running environment: haisi3516ev200, cross compile: arm-himix100-linux-gcc, kernel: linux-4.9.37
When I run an embedded Linux code, memory begins at 22M, decreases to about 6M slowly, and quickly up to about 22M,and then decreases to about 6M slowly... I thought it would be because of a memory leak, but I can't figure it out. I user free to check memery, like this (uint:k):
22284
21900
21772
21324
19500
19176
18792
18056
16904
16296
15560
14888
14216
12680
11448
10008
8536
6992
6756
22352
20656
20336
19472
18672
17968
15440
11040
69609
22088
The code is simple.
void main()
{
int sockfd;
char ip_addr[IP_ALEN] = {0};
struct sockaddr_in s_addr_in;
char buffer[1024];
int ret = -1;
int len =0;
int conn_state, i;
int32_t mach = 0,macl = 0;
printf("\n thread send device info start \n");
while(1)
{
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
printf("socket error! thread exit \n");
break;
}
memset(&s_addr_in,0,sizeof(s_addr_in));
s_addr_in.sin_addr.s_addr = inet_addr(ini_info->server_ip);
s_addr_in.sin_family = AF_INET;
s_addr_in.sin_port = htons(SERVER_PORT);
//set tcp keepalive
set_tcp_keep_alive(sockfd);
//connet
conn_state = 0;
for(i = 0; i< 200; i++)
{
usleep(10000);
ret = connect(sockfd,(struct sockaddr *)(&s_addr_in),sizeof(s_addr_in));
if(ret == 0)
{
conn_state = 1;
ret = local_inet(ini_info->net_type,ip_addr,&mach,&macl);
if (0 != ret){
printf("get local ip failed");
return NULL;
}
printf("ip_addr = %s, mac = %06x%06x \n", ip_addr, mach,macl);
break;
}
}
if(conn_state == 0)
{
printf("connect failed \n");
close(sockfd);
continue;
}
printf("connect success \n");
int cnt = 0;
while(1)
{
sleep(5);
memset(buffer,0,sizeof(buffer));
snprintf(buffer, sizeof(buffer), "{\"type\":0,\"opcode\":1,\"information\": {\"id\":\"112233445566\"},\"status\":{\"power\":100,\"temp\":56}}");
cnt = strlen(buffer);
printf("buffer = %s, strlen(buffer) = %d\n", buffer, cnt);
ret = write(sockfd,buffer,cnt);
if(ret <= 0)
{
printf("send status info error \n");
break;
}
printf("report device info to ai-box success \n");
}
close(sockfd);
}
return ;
}
I've tried to put \0 at the end of the message, but that didn't work. I've also put the terminating char when receiving the socket in the client side but that didn't work either. Here is an image of the console:
server side:
char u[BUFFER]
char *msg = "You are required to enter username:\n\n";
send(clie, msg, strlen(msg), 0);
// not shown on console
char *u_msg = "Username: ";
send(clie, u_msg, strlen(u_msg), 0);
recv(clie, u, sizeof(u), 0);
client-side
char srecv[BUFFER]; // BUFFER = 1024
while (1) {
bytes = recv(ser, & srecv, BUFFER, 0);
srecv[bytes] = '\0';
printf("%s", srecv);
scanf("%s", ssend);
if (send(ser, ssend, strlen(ssend), 0) == -1) {
perror("send\n");
exit(1);
}
}
Since there are multiple '\n' characters in your server's messaging, that is not sufficient to let the client know when each message has finished being received. You should either:
send a message's length before sending the actual message.
send a unique terminator at the end of each message (in your example, the null terminator will suffice).
Either way will allow the client to keep reading and displaying a message's bytes to the console until the true end of message has been reached, BEFORE then reading the user's response from the console. The client MUST wait to receive both messages in their entirety before then calling scanf().
There is no 1:1 relationship between send() and recv() in TCP, you MUST be prepared to handle that. Both functions MAY return fewer bytes than requested, so both functions must be called in loops until all expected bytes are sent/received. And messages MUST be explicitly framed by the sender in such a way that the receiver knows when a message actually ends.
Try something more like this instead:
Common code for both sides:
int sendAll(int sckt, const void *data, size_t size)
{
const char *pdata = (const char*) data;
while (size > 0)
{
ssize_t sent = send(sckt, pdata, size, 0);
if (sent < 0) return -1;
pdata += sent;
size -= sent;
}
return 0;
}
int recvAll(int sckt, void *data, size_t size)
{
char *pdata = (char*) data;
while (size > 0)
{
ssize_t recvd = recv(sckt, pdata, size, 0);
if (recvd <= 0) return recvd;
pdata += recvd;
size -= recvd;
}
return 1;
}
int sendMsg(int sckt, const char *msg)
{
uint32_t msglen = strlen(msg);
uint32_t temp = htonl(msglen);
int ret = sendAll(sckt, &temp, sizeof(temp));
if (ret == 0) ret = sendAll(sckt, msg, msglen);
return ret;
}
int recvMsg(int sckt, char **msg)
{
*msg = NULL;
uint32_t msglen = 0;
int ret = recvAll(sckt, &msglen, sizeof(msglen));
if (ret <= 0) return ret;
msglen = ntohl(msglen);
char *pmsg = (char*) malloc(msglen+1);
if (!pmsg) return NULL;
if (msglen > 0)
{
ret = recvAll(sckt, pmsg, msglen);
if (ret <= 0)
{
free(pmsg);
return ret;
}
}
pmsg[msglen] = '\0';
*msg = pmsg;
return 1;
}
Alternatively:
int sendMsg(int sckt, const char *msg)
{
if (!msg) msg = "\0";
int size = strlen(msg) + 1;
do
{
ssize_t sent = send(sckt, msg, size, 0);
if (sent < 0) return -1;
msg += sent;
size -= sent;
}
while (size > 0);
return 0;
}
int recvMsg(int sckt, char **msg)
{
char c, buf[1024];
int inbuf = 0;
char *pmsg = NULL;
int msglen = 0;
*msg = NULL;
do
{
ssize_t ret = recv(sckt, &c, 1, 0);
if (ret <= 0)
{
if (pmsg) free(pmsg);
return ret;
}
if (c == '\0')
break;
if (inbuf == sizeof(buf))
{
char *newmsg = (char*) realloc(msg, msglen + inbuf + 1);
if (!newmsg)
{
if (pmsg) free(pmsg);
return -1;
}
memcpy(buf, &newmsg[msglen], inbuf);
newmsg[msglen + inbuf] = '\0';
pmsg = newmsg;
msglen += inbuf;
inbuf = 0;
}
buf[inbuf] = c;
++inbuf;
}
while (1);
if ((inbuf > 0) || (msglen == 0))
{
char *newmsg = (char*) realloc(msg, msglen + inbuf + 1);
if (!newmsg)
{
if (pmsg) free(pmsg);
return -1;
}
if (inbuf > 0) memcpy(buf, &newmsg[msglen], inbuf);
newmsg[msglen + inbuf] = '\0';
pmsg = newmsg;
}
*msg = pmsg;
return 1;
}
Server side:
sendMsg(clie, "You are required to enter username:\n\n");
sendMsg(clie, "Username: ");
char *u;
if (recvMsg(clie, &u) == 1)
{
...
free(u);
}
Client side:
char *msg;
while (1) {
ret = recvMsg(ser, &msg);
if (ret <= 0)
{
if (ret < 0)
{
perror("recvMsg\n");
exit(1);
}
break;
}
printf("%s", msg);
if (strcmp(msg, "Username: ") == 0)
{
scanf("%s", ssend);
if (sendMsg(ser, ssend) == -1)
{
perror("sendMsg\n");
exit(1);
}
}
free(msg);
}
I want to send and receive data from device to pc and vice versa. I am sending the string, but not able to receive it fully. Example: Sent string is Hello, and the output is:
Received:H
Error in read! e = -4 and received = 5
#include <string.h>
#include<stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
#define BULK_EP_OUT 0x01
#define BULK_EP_IN 0x81
/*find these values using lsusb -v*/
uint16_t VENDOR = 0x0483;
uint16_t PRODUCT = 0x5740;
int main(void)
{
int ret = 1; //int type result
struct libusb_device **usb_dev;
struct libusb_device_descriptor desc;
struct libusb_device_handle *handle = NULL;
struct device_handle_expected;
//struct libusb_device_handle device_expected_handle = NULL;
struct libusb_device *dev, *dev_expected;
char *my_string, *my_string1;
int e = 0, config;
char found = 0;
int transferred = 0;
int received = 0;
int length = 0;
int i=0;
int count;
/*struct libusb_device *dev;
struct libusb_device **devs;
struct dev_expected;*/
// Initialize libusb
ret = libusb_init(NULL);
if(ret < 0)
{
printf("\nFailed to initialise libusb\n");
return 1;
}
else
printf("\nInit successful!\n");
// Get a list of USB devices
count = libusb_get_device_list(NULL, &usb_dev);
if (count < 0)
{
printf("\nThere are no USB devices on the bus\n");
return -1;
}
printf("\nToally we have %d devices\n", count);
while ((dev = usb_dev[i++]) != NULL)
{
ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0)
{
printf("Failed to get device descriptor\n");
libusb_free_device_list(dev, 1);
break;
}
e = libusb_open(dev, &handle);
if (e < 0)
{
printf("Error opening device\n");
libusb_free_device_list(dev, 1);
libusb_close(handle);
break;
}
if(desc.idVendor == 0x0483 && desc.idProduct == 0x5740)
{
found = 1;
break;
}
}//end of while
if(found == 0)
{
printf("\nDevice NOT found\n");
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
return 1;
}
else
{
printf("\nDevice found");
// dev_expected = dev;
//device_handle_expected = handle;
}
e = libusb_get_configuration(handle, &config);
if(e!=0)
{
printf("\n***Error in libusb_get_configuration\n");
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
return -1;
}
printf("\nConfigured value: %d", config);
if(config != 1)
{
libusb_set_configuration(handle, 1);
if(e!=0)
{
printf("Error in libusb_set_configuration\n");
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
return -1;
}
else
printf("\nDevice is in configured state!");
}
if(libusb_kernel_driver_active(handle, 0) == 1)
{
printf("\nKernel Driver Active");
if(libusb_detach_kernel_driver(handle, 0) == 0)
printf("\nKernel Driver Detached!");
else
{
printf("\nCouldn't detach kernel driver!\n");
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
return -1;
}
}
e = libusb_claim_interface(handle, 0);
if(e < 0)
{
printf("\nCannot Claim Interface");
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
return -1;
}
else
printf("\nClaimed Interface\n");
int nbytes = 64;
my_string = (char *) malloc(nbytes + 1);
my_string1 = (char *) malloc(nbytes + 1);
memset(my_string, '\0', 64);//The C library function void (an unsigned char) to the first n characters of the string pointed to, by the argument str.
memset(my_string1, '\0', 64);
strcpy(my_string, "Hello");
length = strlen(my_string);
printf("\nTo be sent: %s", my_string);
e = libusb_bulk_transfer(handle, BULK_EP_OUT, my_string, length, &transferred, 0);
if(e == 0 && transferred == length)
{
printf("\nWrite successful!");
printf("\nSent %d bytes with string: %s\n", transferred, my_string);
}
else
printf("\nError in write! e = %d and transferred = %d\n", e, transferred);
// sleep(3);
i = 0;
for(i = 0; i <= length; i++)
{
e = libusb_bulk_transfer(handle, BULK_EP_IN, my_string1,length, &received, 0); //64: Max Packet Length
if(e == 0 && received == length)
{
printf("\nReceived:");
printf("%c", my_string1[i]);
sleep(5);
}
else
{
printf("\nError in read! e = %d and received = %d bytes\n", e, received);
return -1;
}
}
libusb_release_interface(handle, 0);
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
libusb_exit(NULL);
printf("\n");
return 0;
}
Pretty certain the bulk in transfer will transfer the entire buffer at once(up to 64--or 512 if you're doing high speed--bytes), not a byte at a time.
You're iterating over the size of the expected buffer and doing a bulk in for each byte, and only printing out the first byte.
Get rid of the for loop on the read and change your printf() to be printf("%s\n",my_string1);
I have looked at the similar threads but can't seem to find anything that could solve my problem.
I am programming a server that could send an image(jpg) file from the path sent to it from the client. I am using send/recv functions in C for that.
I read files one chunk of data at a time and send it to the client that receives the contents and writes them at some location to build the file.
Problem is 'recv' doesn't receive the number of bytes sent by the 'send'.
As part of debugging, I have tried different buffer sizes and '128' buffer size doesn't give me any problem, and the file is successfully transferred and built.
However, for '32' and '64' bit buffers, 'recv' receives '32' bit or '64' bit data at the last chunk, even though the data sent by the server is less than either '32' bit or '64' bit. And, for '256', '512', '1024' so on, 'recv' returns ONLY '128' bits at EXACTLY one of the responses, even though the server sends complete chunk, i.e. '256' or'512', depending on the buffer size.
I'll appreciate any advise for debugging. Following code is for the relevant parts only, but I can provide more, should someone requires it.
//Client Code
#define BUFFER_SIZE 4096
#define HEADER_LEN 512
const char * const scheme = "GETFILE";
const char* const method = "GET";
const char * const end_marker = "\\r\\n\\r\\n";
struct gfcrequest_t
{
int filelen;
char cport[12];
char servIP[50];
gfstatus_t ret_status;
char spath[1024];
int tot_bytes;
char filecontent[BUFFER_SIZE];
void (*fl_handler)(void *, size_t, void *);
void * fDesc;
void (*head_handler)(void *, size_t, void *);
void * headarg;
};
static pthread_mutex_t counter_mutex;
gfcrequest_t *gfc;
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET)
{
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
static char *stringFromError(gfstatus_t stat)
{
static const char *strings[] = {"GF_OK", "GF_FILE_NOT_FOUND", "GF_ERROR", "GF_INVALID"};
return strings[stat];
}
int getFileRequestHeader(char * req_header)
{
return snprintf(req_header,HEADER_LEN, "%s%s%s%s", scheme, method,gfc->spath, end_marker);
// return snprintf(req_header,HEADER_LEN, "%s%s%s%s", scheme, method,"/courses/ud923/filecorpus/yellowstone.jpg", end_marker);
}
gfcrequest_t *gfc_create()
{
gfc = (gfcrequest_t*)malloc(1* sizeof(gfcrequest_t));
return gfc;
}
void gfc_set_server(gfcrequest_t *gfr, char* server)
{
strcpy(gfr->servIP, server);
}
void gfc_set_path(gfcrequest_t *gfr, char* path)
{
strcpy(gfr->spath, path);
}
void gfc_set_port(gfcrequest_t *gfr, unsigned short port)
{
snprintf(gfr->cport,12, "%u",port);
}
void gfc_set_headerfunc(gfcrequest_t *gfr, void (*headerfunc)(void*, size_t, void *))
{
gfr->head_handler = headerfunc;
}
void gfc_set_headerarg(gfcrequest_t *gfr, void *headerarg)
{
/*have to change this...*/
gfr->headarg = headerarg;
}
int isEndMarker(char *iheader, int start)
{
char *marker = "\\r\\n\\r\\n";
int i = 0; int ind=0;
while (ind <= 7)
{
if (iheader[start++] == marker[ind++])
{
continue;
}
return 0;
}
return 1;
}
int getFileLen(char *resp_header, gfcrequest_t *gfr)
{
char scheme[8];
char status[4];
int istatus;
char filelen[12];
int contentlen = 0;
int fileindex = 0;
char end_marker[12];
int fexit=0;
int end=0;
sscanf(resp_header, "%7s%3s", scheme, status);
istatus = atoi(status);
if (istatus == 200)
{
gfr->ret_status = GF_OK;
}
else if (istatus == 400)
{
gfr->ret_status = GF_FILE_NOT_FOUND;
}
else if (istatus == 500)
{
gfr->ret_status = GF_ERROR;
}
if (!strcmp(scheme, "GETFILE") && (istatus == 200 || istatus == 400 || istatus == 500))
{
int index = 10;
while(1)
{
if (resp_header[index] == '\\')
{
end = isEndMarker(resp_header, index);
}
if (end)
break;
filelen[fileindex++] = resp_header[index++];
}
filelen[fileindex] = '\0';
}
int head_len = strlen(scheme) + strlen(status) + strlen(filelen) + 8;
return atoi(filelen);
}
void gfc_set_writefunc(gfcrequest_t *gfr, void (*writefunc)(void*, size_t, void *))
{
gfr->fl_handler = writefunc;
}
void gfc_set_writearg(gfcrequest_t *gfr, void *writearg)
{
gfr->fDesc = writearg;
}
int gfc_perform(gfcrequest_t *gfr){
struct addrinfo hints, *servinfo, *p;
int sockfd, rv, totalBytesRcvd;
char req_header[HEADER_LEN];
int bytesRcvd;
int header_len;
char s[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof(hints));
memset(req_header,0,sizeof(req_header));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; //use my IP
if ((rv = getaddrinfo(NULL, gfr->cport, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1)
{
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL)
{
fprintf(stderr, "client: failed to connect\n");
return 2;
}
//printf("connected...\n");
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof(s));
//Ahsan
// printf("Before getFileRequestHeader...\n");
header_len = getFileRequestHeader(req_header);
//printf("Header Description:%s, Header Len: %u\n", req_header, header_len);
if (send(sockfd, req_header, header_len, 0) != header_len)
perror("send() sent a different number of bytes than expected");
if ((bytesRcvd = recv(sockfd, gfr->filecontent, BUFFER_SIZE, 0)) <= 0)
perror("recv() failed or connection closed prematurely");
//printf("Header Received: %s\n", gfr->filecontent);
gfr->filelen = getFileLen(gfr->filecontent, gfr);
//printf("File Length: %d\n", gfr->filelen);
/* Receive the same string back from the server */
int req_no=1;
gfr->tot_bytes = 0;
while ( 1 )
{
printf("Request: %d ", req_no++);
ssize_t nb = recv( sockfd, gfr->filecontent, BUFFER_SIZE, 0 );
if ( nb == -1 ) err( "recv failed" );
if ( nb == 0 ) {printf("zero bytes received...breaking");break;} /* got end-of-stream */
gfr->fl_handler(gfr->filecontent, nb, gfr->fDesc);
gfr->tot_bytes += nb;
printf("Received Bytes: %zd Total Received Bytes: %d\n", nb, gfr->tot_bytes);
}
return 0;
}
/*
* Returns the string associated with the input status
*/
char* gfc_strstatus(gfstatus_t status)
{
return stringFromError(status);
}
gfstatus_t gfc_get_status(gfcrequest_t *gfr){
return gfr->ret_status;
}
size_t gfc_get_filelen(gfcrequest_t *gfr)
{
return gfr->filelen;
}
size_t gfc_get_bytesreceived(gfcrequest_t *gfr)
{
return gfr->tot_bytes;
}
void gfc_cleanup(gfcrequest_t *gfr)
{
free(gfr);
gfr=NULL;
}
void gfc_global_init()
{
;
// pthread_mutex_lock(&counter_mutex);
//
// gfc = (gfcrequest_t*)malloc(1* sizeof(gfcrequest_t));
//
// pthread_mutex_unlock(&counter_mutex);
}
void gfc_global_cleanup()
{
;
// pthread_mutex_lock(&counter_mutex);
//
// free(gfc);
//
// pthread_mutex_unlock(&counter_mutex);
}
//Server Code
struct gfcontext_t
{
int sockfd;
int clntSock;
};
struct gfserver_t
{
char port[12];
unsigned short max_npending;
char fpath[256];
ssize_t (*fp_handler)(gfcontext_t *ctx, char *, void*);
int *handler_arg;
};
/*Variable decalation*/
static gfserver_t *gfserv;
static gfcontext_t *gfcontext;
int isEndMarker(char *iheader, int start)
{
char *marker = "\\r\\n\\r\\n";
int i = 0; int ind=0;
while (ind <= 7)
{
if (iheader[start++] == marker[ind++])
{
//printf("Header Char:%c Marker:%c\n", iheader[start], marker[ind]);
//start++;
continue;
}
return 0;
}
//printf("Its a marker!!!\n");
return 1;
}
int parseHeader(char *iheader, gfserver_t *gfs, int hlen)
{
//"GETFILEGET/courses/ud923/filecorpus/road.jpg\r\n\r\n"
char scheme[8];
char method[4];
// char path[256];
int pathindex = 0;
char end_marker[12];
int end = 0;
int fexit=0;
sscanf(iheader, "%7s%3s", scheme, method);
int i=10;
if (iheader[i] == '/')
{
// printf("Path has started...\n");
if (!strcmp(scheme, "GETFILE") && !strcmp(method, "GET"))
{
while(1)
{
if (iheader[i] == '\\')
{
end = isEndMarker(iheader, i);
}
if (end)
break;
gfs->fpath[pathindex++] = iheader[i++];
}
gfs->fpath[pathindex] = '\0';
}
}
printf("Scheme: %s Method:%s Path:%s\n", scheme, method, gfs->fpath);
return 0;
}
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET)
{
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
ssize_t gfs_sendheader(gfcontext_t *ctx, gfstatus_t stat, size_t file_len)
{
char resp_header[MAX_REQUEST_LEN];
char end_marker[12] = "\\r\\n\\r\\n";
sprintf(resp_header, "GETFILE%d%zd%s",stat, file_len, end_marker);
printf("Response: %s\n", resp_header);
if (send(ctx->clntSock, resp_header, MAX_REQUEST_LEN, 0) != MAX_REQUEST_LEN)
perror("send() failed");
return 0;
}
ssize_t gfs_send(gfcontext_t *ctx, void *data, size_t len)
{
size_t total = 0;
size_t bytesLeft = len;
size_t n;
int debug_req=1;
while (total < len)
{
n = send(ctx->clntSock, data+total, bytesLeft, 0);
if (n == -1) { printf("Nothing to send...\n"); break; }
fprintf(stderr, "Tries: %d Bytes Sent: %zu\n", debug_req++, n);
total += n;
bytesLeft -= n;
}
// if ( shutdown( ctx->clntSock, SHUT_WR ) == -1 ) err( "socket shutdown failed" );
return total;
}
void gfs_abort(gfcontext_t *ctx){
close(ctx->clntSock);
close(ctx->sockfd);
free(ctx);
free(gfserv);
perror("aborting...");
exit(1);
}
gfserver_t* gfserver_create()
{
gfserv = (gfserver_t*) malloc(1 * sizeof(gfserver_t));
gfcontext = (gfcontext_t*) malloc(1*sizeof(gfcontext_t));
return gfserv;
}
void gfserver_set_port(gfserver_t *gfs, unsigned short port)
{
//set port number in gfs structure
snprintf(gfs->port,12, "%u",port);
}
void gfserver_set_maxpending(gfserver_t *gfs, int max_npending)
{
//set maxpending connections
gfs->max_npending = max_npending;
}
void gfserver_set_handler(gfserver_t *gfs, ssize_t (*handler)(gfcontext_t *, char *, void*))
{
gfs->fp_handler = handler;
}
void gfserver_set_handlerarg(gfserver_t *gfs, void* arg)
{
gfs->handler_arg = (int *)arg;
}
void gfserver_serve(gfserver_t *gfs)
{
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage clntAddr; //connectors address information
socklen_t clntSize;
int yes = 1;
char s[INET6_ADDRSTRLEN];
int rv;
int rcvMsg = 0;
char recvBuff[MAX_REQUEST_LEN];
char *req_path;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; //using stream socket instead of datagrams
hints.ai_flags = AI_PASSIVE; //use my IP
if ((rv = getaddrinfo(NULL, gfs->port, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((gfcontext->sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("server: socket");
continue;
}
//get rid of 'address already in use' error.
if (setsockopt(gfcontext->sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
if (bind(gfcontext->sockfd, p->ai_addr, p->ai_addrlen) == -1)
{
close(gfcontext->sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL)
{
fprintf(stderr, "server: failed to bind.\n");
return 2;
}
freeaddrinfo(servinfo); // no need of servinfo structure anymore
if (listen(gfcontext->sockfd, gfs->max_npending) == -1)
{
perror("listen");
exit(1);
}
//printf("server: waiting for connetions...\n");
while(1)
{
clntSize = sizeof(clntAddr);
gfcontext->clntSock = accept(gfcontext->sockfd, (struct sockaddr *)&clntAddr, &clntSize);
if (gfcontext->clntSock == -1)
{
perror("accept");
continue;
}
inet_ntop(clntAddr.ss_family, get_in_addr((struct sockaddr *)&clntAddr), s, sizeof(s));
//printf("server: got connection from %s\n", s);
if (!fork())
{ // this is the child process
if ((rcvMsg = recv(gfcontext->clntSock, recvBuff, MAX_REQUEST_LEN, 0)) < 0)
{
perror("recv() failed");
exit(1);
}
/*Still to parse received request...*/
//printf("Recd Header: %s, Recd %d bytes\n",recvBuff, rcvMsg);
/*Parse the received header...*/
int len = parseHeader(recvBuff, gfs, rcvMsg);
//printf("Requested Path: %s\n", gfs->fpath);
if (gfs->fp_handler(gfcontext, gfs->fpath, NULL) < 0)
{
printf("some problem...\n");
}
if ( shutdown( gfcontext->clntSock, SHUT_WR ) == -1 ) err( "socket shutdown failed" );
//close(gfcontext->clntSock);
}
}
}
//Server gf_send is being called from following function handler function:
Handler:
ssize_t handler_get(gfcontext_t *ctx, char *path, void* arg){
int fildes;
size_t file_len, bytes_transferred;
ssize_t read_len, write_len;
char buffer[BUFFER_SIZE];
printf("Path: %s\n", path);
if( 0 > (fildes = content_get(path)))
return gfs_sendheader(ctx, GF_FILE_NOT_FOUND, 0);
/* Calculating the file size */
file_len = lseek(fildes, 0, SEEK_END);
gfs_sendheader(ctx, GF_OK, file_len);
/* Sending the file contents chunk by chunk. */
int req=1;
bytes_transferred = 0;
while(bytes_transferred < file_len){
read_len = pread(fildes, buffer, BUFFER_SIZE, bytes_transferred);
if (read_len <= 0){
fprintf(stderr, "handle_with_file read error, %zd, %zu, %zu", read_len, bytes_transferred, file_len );
gfs_abort(ctx);
return -1;
}
printf("Request No: %d ", req++);
write_len = gfs_send(ctx, buffer, read_len);
if (write_len != read_len){
fprintf(stderr, "handle_with_file write error");
gfs_abort(ctx);
return -1;
}
bytes_transferred += write_len;
}
printf("Total Bytes sent to client: %zu\n", bytes_transferred);
return bytes_transferred;
}
You didn't specify, so I am assuming you are using TCP here (send/receive semantics is different with UDP),
You are suffering from a very common misconception that one send on one end of a TCP socket corresponds to one receive of sent number of bytes on the other end. This is wrong.
In fact, TCP socket is a bi-directional stream of bytes with no notion of messages. One write can correspond to many reads on the other end, and vise versa. Treat it as a stream.
You need to keep number of bytes sent and received as returned from sending and receiving system calls.
It is also important to let the other side know how much data you are sending, so it will know when, say, an image is fully transferred. This is the job of an application-level protocol that you have to either come up with or use an existing one.
Edit 0:
Here is what looks needed even before setting up any meaningful protocol between client and the server.
First the sending code:
size_t total = 0;
while ( total != len ) {
ssize_t nb = send( s, data + total, len - total, 0 );
if ( nb == -1 ) err( "send failed" );
total += nb;
}
if ( shutdown( s, SHUT_WR ) == -1 ) err( "socket shutdown failed" );
/* also need to close client socket, see below */
Then the receiving code:
char buffer[BUFFER_SIZE]; /* somewhere, might be static */
size_t total = 0; /* everything received */
while ( 1 ) {
ssize_t nb = recv( s, buffer, BUFFER_SIZE, 0 );
if ( nb == -1 ) err( "recv failed" );
if ( nb == 0 ) break; /* got end-of-stream */
if ( write( file_fd, buffer, nb ) == -1 ) err( "file write failed" );
total += nb;
}
/* send an ack here */
if ( close( s ) == -1 ) err( "socket close failed" );
if ( close( file_fd )) err( "file close failed" );
printf( "received and saved total of %zu bytes\n", total );
Then your application-level protocol might be as simple as server sending, say, 64-bit file length immediately after accepting new client connection (you need to decide what endianness to use for that), then after sending that many bytes to the client and shutting down writing on the socket, waiting for the client to acknowledge successful receipt of data. That might be that same number back, or just a single byte - up to you, then finally closing the socket. That way the client knows upfront how many bytes to expect, and the server knows that transfer was successful.
After getting this simple version working you can extend it to allow multiple file transfers per connection, and/or dive into IO multiplexing with select(2)/poll(2).
Hope this helps.
First of all: recv() does not always receive the data in the chunks that it was sent by send(), as a matter of fact - it rarely does - because of buffering (for example, you send 256-bytes receive two buffers of 128-bytes each)
Now to your error: I think the problem is that you are not be calling select() with a FD_SET to reset your socket to a "ready to receive" state before calling recv() a second time.
I have a metric-ton of winsock/c-sockets code on my site if you want to dig through it.
Let me know if I can expand on this answer, I'd be happy to provide additional assistance!
gfr->fl_handler(gfr->filecontent, BUFFER_SIZE, gfr->fDesc);
Usual problem. You're assuming the read filled the buffer. It should be:
gfr->fl_handler(gfr->filecontent, bytesRcvd, gfr->fDesc);
I have a Server that contact another Server in order to obtain a file and then send it to the Client. I have write this piece of code (C - Linux) but only the first 4 bytes arrive to the Client.
Someone better than me can see the mistake?
Thank you very much
int Recv_file (int s, int f, char *ptr, size_t maxlen){
int const TIMEOUT = 60; /* 60 seconds */
size_t n;
ssize_t nread;
ssize_t nsend;
char c;
fd_set cset;
struct timeval tval;
int x;
for (n=1; n<maxlen; n++)
{
FD_ZERO(&cset);
FD_SET(s, &cset);
tval.tv_sec = TIMEOUT;
tval.tv_usec = 0;
x = select(FD_SETSIZE, &cset, NULL, NULL, &tval);
if (x==-1) {
perror("select() failed");
return -1; /* -1 = close connection with the client */
}
if (x>0) {
nread=recv(s, &c, 1, 0);
if (nread == 1)
{
*ptr++ = c;
nsend = Send(f,&c,1);
if (nsend != 1) {
return -1; /* close connection with the client */
}
}else if (nread == 0){
*ptr = 0;
return (-1); /* close connection with the client */
}
else
return (-1); /* close connection with the client */
}else{
printf("(It's been %d seconds and I have not received any response",TIMEOUT);
close(s);
return(-1); /* close connection with the client */
}
}
*ptr = 0;
return (n); /* n == maxlen */
}
with:
int Send(int s, char *ptr, size_t nbytes){
size_t nleft;
ssize_t nwritten;
for (nleft=nbytes; nleft > 0; )
{
nwritten = send(s, ptr, nleft, 0);
if (nwritten <=0)
return (nwritten);
else
{
nleft -= nwritten;
ptr += nwritten;
}
}
return (nbytes - nleft); /* number of bytes sent */
}
UPDATE:
While waiting for an answer I modified:
nread=recv(s, &c, 1, 0); in nread=recv(s, &c, sizeof(c), 0);
and
Send(f,&c,1); in Send(f,&c,sizeof(c));
But now I don't receive the last bytes of the file!
Thank you again!
You don't get the last byte because the for loop start at 1
for (n=1; n<maxlen; n++);
// it should be
for (n=0; n<maxlen; n++);
// or either
for (n=1; n<=maxlen; n++);
EDIT: Also, you could read as much bytes as are available not just one by one, in fact you are sending in the correct way,
For example:
int bLeft = maxlen;
while (bLeft > 0)
{
FD_ZERO(&cset);
FD_SET(s, &cset);
tval.tv_sec = TIMEOUT;
tval.tv_usec = 0;
x = select(FD_SETSIZE, &cset, NULL, NULL, &tval);
if (x > 0) {
nread=recv(s, ptr, bLeft , 0);
if (nread > 0)
{
nsend = Send(f, ptr, nread, 0);
if (nsend <= 0) {
return -1; /* close connection with the client */
}
ptr+ = nread;
bLeft -= nread;
}else if (nread == 0){
*ptr = 0;
return (-1); /* close connection with the client */
}
else
return (-1); /* close connection with the client */
}else{
printf("(It's been %d seconds and I have not received any response",TIMEOUT);
close(s);
return(-1); /* close connection with the client */
}
}
// I would not recommended this, you should adhere to a maxlen length
// assuming there is more space could lead to a memory Exception.
ptr++;
*ptr ='\0';
return (maxlen-bLeft);