Sockets won't block

Regan Heath regan at netwin.co.nz
Thu Aug 31 15:27:34 PDT 2006


On Thu, 31 Aug 2006 16:37:02 +0000 (UTC), %u <gdefty at attglobal.net> wrote:
> When I open sockets they don't seem to like blocking, and return  
> immediately
> when I do a 'receive' (with 0 bytes of data of course)

This is due to the receive function's shortcut, see std\socket.d:

		if(!buf.length) //return 0 and don't think the connection closed
			return 0;

you're passing it a 0 length buffer. If you pass 0 for len to the 'recv'  
call it will return an error WSAEINVAL. The comment indicates a desire to  
avoid the error because people assume it means the socket has closed,  
which you could do, if you didn't check the actual error code perhaps.

The solution. Your receive calls need to look something like this:

			buf.length = 100;
			len = otherSock.receive(buf);
			assert(len != Socket.ERROR);
			assert(otherSock.isAlive);
			buf.length = len;
			writefln("Received data (", buf.length , ") '", buf , "'.");

In other words, allocate some space in buf, read data into buf, check for  
errors, set buf length to length of data read, log it to screen.

I also made the client socket blocking with:
   mySock.blocking = true;
after the connect call. Though, from memory sockets are blocking by  
default.

One other thing I changed was your logging here:
   writefln("Sent (", len , ") '", buf , "' and received '", rcvbuf , "'.");
I made this into 2 log lines, the 2nd _after_ the receive call :)

FYI... the client does not need to call 'bind'. It's entirely optional for  
simple outgoing connections. If you do not call bind it will automatically  
bind the first random available local socket. The only time you need to  
call bind is when you want the remote connection to see you as a certain  
ip and/or port.

Regan

> The routine (client and server in 1) is as follows (excuse all the  
> tracing
> 'writefln's and a few artifacts from the original C++ version :-)
>
> ---- code ----
> // $Header: /home/CVS/atm/ATMsock_t.cpp,v 1.1 1980/04/16 23:53:02 graeme  
> Exp $
> // $Header: /home/CVS/atm/ATMsock_t.cpp,v 1.1 1980/04/16 23:53:02 graeme  
> Exp $
>
> // Author:	Graeme Defty
> // $Date: 1980/04/16 23:53:02 $
> /*
> 	This module runs tests on the ATM Socket class.
> */
>
> static const char pgmid[] =
> 	"$Id: ATMsock_t.cpp,v 1.1 1980/04/16 23:53:02 graeme Exp $";
>
> // $Source: /home/CVS/atm/ATMsock_t.cpp,v $ //
>
> //#include <fstream>
> //#include <signal.h>
> //#include <unistd.h>
> import std.c.time;
> import std.stdio;
> import std.string;
> import std.socket;
>
> //#include "ATMsock.h"
>
> //#include "assure.h"
>
> // ============ Don't think we need these any more ==========
> //static void
> //sig_h(int signo) {
> //	cout << "Caught signal " << signo << endl;
> //	if (signo == SIGINT) exit(0);
> //}
> // ========================================================
>
> int
> main (char[][] args) {
>
> 	int portnum = 1234;
> 	char [] buf;
> 	char [] rcvbuf;
> 	Socket	mySock;
> 	InternetAddress myAddr, farAddr;
> 	int len;
> 	int count;
> //	struct sigaction sigact;
> //	struct sigaction oldsigact;
>
> // first handle the arguments . . .
> 	if (args.length>2) {
> 		portnum = atoi(args[2]);
> 	}
> 	writefln("Using port number " , portnum , ".");
>
> 	// === Signal handling seems to be unneccessary now ====
>
> // then set up signal handling . . .
> //	sigact.sa_handler	= sig_h;
> //	sigemptyset (&sigact.sa_mask);
> //	sigact.sa_flags	= 0;
> //	for (len=1; len<48; len++) {
> //		if (sigaction(len, &sigact, &oldsigact) == -1) {
> //			perror ("Catching Signal");
> //		} else {
> //			cout << "Signal " << len << " set." << endl;
> //		}
> //	}
>
> 	if (args.length>1 && args[1] == "s") {
>
> 		writefln("Test begins for server . . .");
>
> 		myAddr = new InternetAddress("127.0.0.1", portnum);
> 		mySock = new Socket(AddressFamily.INET, SocketType.STREAM);
> 		writefln("Server created . . .");
> 		mySock.bind(myAddr);
> 		writefln(". . . and bound . . .");
> 		mySock.listen(5);
> 		writefln(". . . and listening.");
>
> 		while (true) {
> 			Socket otherSock = mySock.accept();
> 			assert(otherSock.isAlive);
> 			writefln("Accepted a connection . . .");
> 			writefln("Far address is ", otherSock.remoteAddress);
>
> 			otherSock.blocking = true;
> 			assert(otherSock.isAlive);
> 			sleep(1);
>
> 			len = otherSock.receive(buf);
> 			assert(len != Socket.ERROR);
> 			assert(otherSock.isAlive);
> 			writefln("Received data (", len , ") '", buf , "'.");
>
> 			otherSock.send(buf);
> 			assert(otherSock.isAlive);
> 			writefln("Sent that data . . .");
> //			mySock.close;
> //			writefln(". . . and closed the socket.");
> 		}
>
> 	} else {
> 		writefln("Test begins for client . . .");
>
> 		myAddr = new InternetAddress("127.0.0.1", portnum);
> 		farAddr = new InternetAddress("127.0.0.1", 1234);
>
> 		for (count = 0; count < 12 ; count++) {
> 			if (count % 1000 == 0) {writefln("Done " , count);}
>
> 			mySock = new Socket(AddressFamily.INET, SocketType.STREAM);
> 			assert(mySock.isAlive);
> 			writefln("Client created . . .");
>
> 			mySock.bind(myAddr);
> 			assert(mySock.isAlive);
> 			writefln(". . . and bound . . .");
>
> 			mySock.connect(farAddr);
> 			assert(mySock.isAlive);
> 			writefln(". . . and connected.");
>
> 			writefln("Far address is ", mySock.remoteAddress);
>
> 			buf = format("This is data line ", count);
> 			len = mySock.send(buf);
> 			assert(mySock.isAlive);
> 			writefln("Sent (", len , ") '", buf , "' and received '", rcvbuf ,  
> "'.");
>
> 			len = mySock.receive(rcvbuf);
> 			assert(mySock.isAlive);
> //			assert (buf == rcvbuf, "Sent and received data different!");
> 			if (buf != rcvbuf) {
> 				writefln("ERROR: Sent '", buf , "' and received '", rcvbuf , "'.");
> 			}
> 			mySock.close();
> 			sleep(10);
> 		}
> 	}
> 	writefln("Test Done!");
> 	return 0;
> }
>
> ---- end code ----
>
> I would appreciate any guidance.
>
> Thanks,
>
> graeme




More information about the Digitalmars-d-learn mailing list