Problem receiving the entire message using TCP socket

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If this is a wrong mailling list to send this question, I apologise.
Please let me know the right mailing list I can post the question. I am
stuck at the problem for some time.

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);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pradeep Padala");
~
--
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux