LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-15-2010, 06:40 PM   #1
myuboot
LQ Newbie
 
Registered: Mar 2010
Posts: 3

Rep: Reputation: 0
Problem receiving the entire message using TCP socket


I am trying to create a socket server in user space and a client in
kernel space and send big messages (a little over 64kbytes) between
them.

I used an kernel socket programming examplefrom this link -
http://www.linuxjournal.com/article/7660 for the kernel client side.

When the client in kernel side sends out a 64k message, usually, the
server side in the user space will get a big part of the message, but
will stuck at waiting for the recv() to return to get the rest of it.
So I am chopping the packets into small pieces, 1000 bytes each to send
to the server. But only some times, the packets will all arrive at the
server/receiver side, and the server and assemble the whole message.
Many times, the server is stuck at waiting for the last a couple of byte
from the sending side. From the sending side printk log, it has already
sent every thing.

I am attaching some log here, and the code at the end. Can someone give
me some idea on how to force the data to arrive at the receiver side?
Maybe the kernel on the receiver side is holding part of the packet so
the receiver program in the user space is blocked at recv()? I tried
adding TCP_NODELAY on sockets on both sender and receiver sides, both it
did not help.

Thanks a lot, Andrew

I got a connection from (10.16.216.217 , 1489)
- Server side stuck on recv()-
bytes_recieved 17384
bytes_recieved 32768, total received 50152, expected 65540
=======================================
- Client side is already done -
30626.382617] send length 1000
[30626.382618] left 1000
[30626.382620] i:64
[30626.382621] send length 1000
[30626.382623] left 1000
[30626.382624] i:65
[30626.382626] send length 540
[30626.382627] left 540
[30626.382629] i:66

Here is server side code -
while(1)
{

sin_size = sizeof(struct sockaddr_in);

connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);

printf("\n I got a connection from (%s , %d)",
inet_ntoa(client_addr.sin_addr),(client_addr.sin_port));

bytes_recieved = total_received = recv(connected,
recv_data,sizeof(recv_data),0);
printf("\nbytes_recieved %d\n", bytes_recieved);
command = (((struct long_message*)recv_data)->command);
if ((READ_RESP == command) || (WRITE == command))
{
expected_len = sizeof(struct long_message);
} else
{
expected_len = sizeof(struct short_message);
}

p = &recv_data[bytes_recieved];
while (expected_len > total_received)
{
bytes_recieved = recv(connected, p, expected_len-total_received,0);
total_received += bytes_recieved;
printf("\nbytes_recieved %d, total received %d, expected %d\n",
bytes_recieved, total_received, expected_len);
p += bytes_recieved;
}

int send_sync_buf (struct socket *sock, const char *buf,
const size_t length, unsigned long flags)
{
struct msghdr msg;
struct iovec iov;
int len, written = 0, left = length;
mm_segment_t oldmm;

printk("send length %d \n", length);
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = flags;

oldmm = get_fs(); set_fs(KERNEL_DS);

repeat_send:
printk("left %d \n", left);
msg.msg_iov->iov_len = left;
msg.msg_iov->iov_base = (char *) buf + written;

len = sock_sendmsg(sock, &msg, left);
if ((len == -ERESTARTSYS) || (!(flags & MSG_DONTWAIT) &&
(len == -EAGAIN)))
goto repeat_send;
if (len > 0) {
printk("%d sent\n", len);
written += len;
left -= len;
if (left)
goto repeat_send;
}
set_fs(oldmm);
return written ? written : len;
}

int my_sys_call()
{
struct sockaddr_in saddr, daddr;
struct socket *control= NULL;

int i,r = -1, ret, left;
char *response = kmalloc(SNDBUF, GFP_KERNEL);
char *reply = kmalloc(RCVBUF, GFP_KERNEL);

char *a, *p;
char address[128];
int len = 0, total_written = 0;
char temp[64];

// if(current->uid != 0)
if(current->cred->uid != 0)
return r;

r = sock_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, &control);
// r = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &control);
if (r < 0) {
printk(KERN_ERR FTP_STRING "error %d creating socket.\n", r);
goto err;
}

if (setsockopt(r, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
}

memset(&saddr,0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PORT);
saddr.sin_addr.s_addr = 0x0100007f;

r = control->ops->connect(control, (struct sockaddr *) &saddr,
sizeof(saddr), O_RDWR);
if (r && (r != -EINPROGRESS)) {
printk(KERN_ERR FTP_STRING "connect error: %d\n", r);
goto err;
}
printk("post connect\n");

long_send_msg.command = (WRITE);
init_data(long_send_msg.data);

left = sizeof(struct long_message);
p = (char *)&long_send_msg;
i = 1;
while (left > 0)
{
if (left > SEGMENT_SIZE)
{
left -= SEGMENT_SIZE;
send_sync_buf(control, p, SEGMENT_SIZE, MSG_DONTWAIT);
p += SEGMENT_SIZE;
printk("i:%d\n", i++);
} else
{
send_sync_buf(control, p, left, MSG_DONTWAIT);
printk("i:%d\n", i++);
break;
}
}

....
}

static int ftp_init(void)
{

printk(KERN_INFO FTP_STRING "Starting ftp client module\n");
my_sys_call();
return 0;
}

static void ftp_exit(void)
{
printk(KERN_INFO FTP_STRING "Cleaning up ftp client module, bye !\n");
//sys_call_table[223] = sys_ni_syscall;
}

module_init(ftp_init);
module_exit(ftp_exit);
...
 
Old 04-15-2010, 11:17 PM   #2
paulsm4
LQ Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
Hi -

This seems to be the heart of your receive code:
Code:
  while (expected_len > total_received)
  {
    bytes_received = recv(connected, p, expected_len-total_received,0);
    total_received += bytes_received ;
    printf("\nbytes_received %d, total received %d, expected %d\n",
      bytes_received , total_received, expected_len);
    p += bytes_received ;
  }
And it's exactly right. You should *not* expect to be able to read the entire (arbitrarily long) message in a single "recv()" - and you're correctly dealing with that fact. Good!

So what's going wrong?

I don't know.

Maybe you *are* receiving the message ... but the code isn't *printing out* when you receive it.

Suggestion: try (unbuffered) "fprintf (stderr)" - throughout your send and receive code - and see if it makes any difference:
Code:
  while (expected_len > total_received)
  {
    bytes_received = recv(connected, p, expected_len-total_received,0);
    total_received += bytes_received ;
    fprintf(stderr, "\nbytes_received %d, total received %d, expected %d\n",
      bytes_received , total_received, expected_len);
    p += bytes_received ;
  }
Another suggestion:
Install Wireshark, take a trace, and see what's actually going over the wire.
 
Old 04-17-2010, 02:58 PM   #3
myuboot
LQ Newbie
 
Registered: Mar 2010
Posts: 3

Original Poster
Rep: Reputation: 0
Thanks for the suggestion.

I finally figured out the reason. In the sender/client code in kernel, I originally send the flag MSG_DONTWAIT. After I change it to 0, the message can go through fine even without breaking the message into small segments.

Here is the change to be exact -
From:
send_sync_buf(control, p, left, MSG_DONTWAIT);
to:
send_sync_buf(control, p, left, 0);
I suspect, that is because if I don't wait for the function to return, the kernel can't handle all 64k buffer all at once?

Also, with Wireshark I observe that, the number of packets sent over ethernet, and amount of data in each packets are changing, and irrelevant to the segment size I sent using the send_sync_buf functions. Regardless of the segment size I am using, some of the packets sent over Ethernet are very small such as 4 bytes, some are big such as 16k.

thanks, Andrew.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
port reuse problem :TCP socket sweetytweety Linux - Newbie 1 05-22-2008 04:05 AM
message size TCP socket ibanezul Linux - Networking 2 10-23-2007 04:07 PM
TCP socket problem maprich Linux - Networking 1 05-08-2006 12:50 PM
How to optimize receiving in a TCP socket? minhsangniit Programming 2 03-12-2006 07:31 PM
Problem to transfer binary file over TCP socket yhus Linux - Networking 3 02-28-2006 08:41 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:31 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration