You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!

Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.

If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.

Having a problem logging in? Please visit this page to clear all LQ-related cookies.

Introduction to Linux - A Hands on Guide

This guide was created as an overview of the Linux Operating System, geared toward new users as an exploration tour and getting started guide, with exercises at the end of each chapter.
For more advanced trainees it can be a desktop reference, and a collection of the base knowledge needed to proceed with system and network administration. This book contains many real life examples derived from the author's experience as a Linux system and network administrator, trainer and consultant. They hope these examples will help you to get a better understanding of the Linux system and that you feel encouraged to try out things on your own.

Sockets - The Black Box

You probably wouldn't be reading this if you didn't know how hard it is to find decent, simple example code.

Me too! And so there have been a few missteps in the previous entries (though they are adequate as demos), but it's all starting to shape up.

Yuh know, all I personally needed was a way to communicate between application so I could do stuff like sending commands to a plotting window. I passed that mark quite a while back.

But this sockets stuff, while it sidesteps some of the problems with pipes and fifos, was such a confounding rats nest of misinformation and bad code that well.... I figured I'd take a whack at it for others that might also just want a simple way for two apps to communicate.

Not that we here at the Mad Science Dept. are immune from writing bug infested code. ;-)

As a matter of fact this sfxz contains netdog-v1.2 which addresses a couple of our own bogies.

But we're well over the hump now. Watch how easily we cab set these sockets up for this test.

And let's see for ourselves what one of these hidden quirks that throws us off the trail is right now.

You don't need libLQ or the gui code, just netdog for this. We'll include the new version/release with the bug fixes mentioned above.

Here's the ans(wer) side of the socket.

file: src/ans.cpp
purpose: source file

Code:

// ans.cpp -- skeleton created by new.main
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <unistd.h> // close() needed by netdog.cpp
#include "../netdog-v1.2/netdog.h"
#include "../netdog-v1.2/netdog.cpp"
void dbg(){} // for a non-moving breakpoint
int main(int argc, char** argv)
{
dbg();
// the usual localhost port so other netdog experiments can play too!
printf("Listening: address '127.0.0.1', port 9999\n");
printf("Ctrl-C to exit\n");
// here's where the 'gotcha' starts. Buffer size is 100. Not a
// problem... yet. See notes in orig.cpp
netdog_t* pobj = netdog_new("127.0.0.1", 9999, 100);
pobj->sock_flags &= ~SOCK_NONBLOCK;
// by default we poll the connection, using NON_BLOCKING for a gui
// to run in the same thread and same loop. We want to override
// this for a terminal app.
netdog_createListener(pobj);
printf("Created listener for the connection\n");
netdog_accept(pobj);
printf("Accepted (created) new connection\n");
for(;;)
{
netdog_receive(pobj);
printf("received: %d bytes\n", pobj->nbytes);
netdog_send(pobj, pobj->indata, pobj->datamax);
printf("sent: %s\n", pobj->outdata);
// Up in one of those lines is the listener/server side of the "gotcha".
}
return 0;
}

Simple enough, right? But you do need to create an additional 'listener' for the answer side of a socket. This is because the 'ans'wer side has two fd's.

file: src/orig.cpp
purpose: source file

Code:

// ans.cpp -- skeleton created by new.main
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <unistd.h> // close() needed by netdog.cpp
#include "../netdog-v1.2/netdog.h"
#include "../netdog-v1.2/netdog.cpp"
void dbg(){} // for a non-moving breakpoint
int main(int argc, char** argv)
{
dbg();
// the usual localhost port so other netdog experiments can play too!
printf("Listening: address '127.0.0.1', port 9999\n");
printf("Ctrl-C to exit\n");
// here's where the 'gotcha' starts. Buffer size is 100. Not a
// problem... yet. But change the 'ans' side to 200 and see
// what happens.
netdog_t* pobj = netdog_new("127.0.0.1", 9999, 100);
pobj->sock_flags &= ~SOCK_NONBLOCK;
// The listener side will have two fd's, one for the listener
// and the other is created by 'accept' which is the other
// side of 'request'.
netdog_request(pobj); // does "connect" internally
for(;;)
{
fgets(pobj->indata, pobj->datamax, stdin);
netdog_send(pobj, pobj->indata, pobj->datamax);
printf("sent: %s\n", pobj->outdata);
netdog_receive(pobj);
printf("received: %s\n", pobj->indata);
// Up in one of those lines is the listener/server side of the "gotcha".
}
return 0;
}

And again, pretty simple, with 'request' on the originators side replacing 'accept' on the answer side.

Now what if...

Change the size of ans.cpp buffer to 200 instead of 100 at around line 21 of the source file and watch what happens. Run it a few times with the original size buffers in both so you get used to what it should look like and then with the double sized buffer for the ans.cpp side.

If you see the problem immediately from just the code (and there's not much of it, so this should be a breeze for a sockets wizz), good for you.

If not.. we are about to discover what's hidden in the black box that nobody talks about.

This self extractor (below) includes netdog-v1.2 and both source files... and a makefile and the mc2.def used to create it. Older netdogs won't work for this, unfortunately.

PS. Thanks to linux questions for their patience with the size of these sockets posts.

This is a really a big deal. There's so little simple yet useable demo code around that this stuff here is pretty important to share.

PPS. Need a hint? Couldn't figure out why the echo went missing half the time and got further and further delayed?

The orig side continues the previous read when it reads and gets a load of zeros until it has received the full amount of data from 'ans'. With a 300 byte buffer size for ans, it would take three reads to get to the second echo, and so on.

Strings like these shouldn't have been a problem because they are short, but then the amount to *send* should NEVER have been datamax. Right? (Et voila!)

Don't blame me, I downloaded the initial code from a university's 'regular' Computer Science Dept. In fact I don't even think they had a Mad Computer Science Dept. and that might have been the problem in the first place. :-)

But that still leaves us with a problem, my fellow wacked out computer freaks. Binary data. How would you solve it? How has it already been solved? And are those the best ways for your own purposes? ;-)

Find out, with netdog! Pretty easy to get working sockets, even with a gui running in the same thread. (see previous recent sockets entries and screen shots.)