www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Trying to make a TCP server, client connects and disconnects

reply "Gan" <avisaria me.com> writes:
I managed to get the client to connect but immediately on the 
server side, this happens:

long length = player.playerSocket.receive(buf);
		if (length == 0) { //No longer connected
			player.playerSocket.shutdown(SocketShutdown.BOTH);
			player.playerSocket.close();
		}

The player's socket receives a 0 length which means the 
connection is dead. Why does that happen?

Here's my full server-side networking code:

module server.networkingandio.networkingcontroller;
import server.server;
import server.player.player;

import std.socket;
import std.stdio;
import core.thread;
import std.range;
import std.traits;
import std.typecons;
import std.typetuple;
import std.algorithm;
import std.concurrency;

class NetworkingController
{
	Server server;

	Player[] players;

	TcpSocket socket;

	this(Server s)
	{
		server = s;
		players = new Player[](0);
		writeln("Server active on port 7777");

		socket = new TcpSocket();
		socket.bind(new InternetAddress(7777));
		socket.listen(100);
		socket.blocking = true;

		spawn(&handleNewConnectionsThread, cast(shared)socket);
	}
	void logic() {
		//Check for new sockets
		bool receivedNewSocket = true;
		while (receivedNewSocket) {
			receivedNewSocket = receiveTimeout(0.msecs,
				(shared NewConnectionMsg message) {
					NewConnectionMsg msg = cast(NewConnectionMsg)message;
					newConnection(msg.socket);
				},
				(shared ReceiveDataMsg message) {
					//Convert data to MessageReader, send to server message 
handler
				}
			);
		}

		//Check for dead sockets
		for (int i = 0; i < players.length; i++) {
			Player p = players[i];
			if (p.playerSocket.isAlive == false) {
				players = players.remove(i);
				i--;
				server.removeConnection(p);
			}
		}
		//Check for socket messages
	}
	void newConnection(Socket conn) {
		Player p = new Player(conn, this);
		players ~= p;
		server.newConnection(p);
		//Set up listener for player socket
		spawn(&handleReceiveDataThread, cast(shared)p);
	}
}
class NewConnectionMsg {
	Socket socket;
	this(Socket socket) {
		this.socket = socket;
	}
}
class ReceiveDataMsg {
	Player player;
	ubyte[] data;
	this(Player player, ubyte[] data) {
		this.player = player;
		this.data = data;
	}
}

void handleNewConnectionsThread(shared TcpSocket s) {
	Socket socket = cast(Socket)s;
	while(socket.isAlive) {
		Socket playerSocket = socket.accept();
		if (playerSocket !is null && playerSocket.isAlive == true) {
			playerSocket.blocking = true;
			ownerTid.send(cast(shared) new NewConnectionMsg(playerSocket));
		}
	}
	scope(exit)socket.close();
}

void handleReceiveDataThread(shared Player p) {
	Player player = cast(Player)p;
	while(player.playerSocket.isAlive) {
		ubyte[] buf = new ubyte[](0);
		long length = player.playerSocket.receive(buf);
		if (length == 0) { //No longer connected
			player.playerSocket.shutdown(SocketShutdown.BOTH);
			player.playerSocket.close();
		} else {
			ownerTid.send(cast(shared) new ReceiveDataMsg(player, buf));
		}
	}
	scope(exit)player.playerSocket.close();
}
Feb 05 2015
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 6 February 2015 at 00:15:15 UTC, Gan wrote:
 		ubyte[] buf = new ubyte[](0);
This is your problem: receive fills a preexisting buffer, and you allocated zero bytes for it to fill, so it can't give you anything. Give it a bigger buffer, I like to use 4096, and it will work better.
Feb 05 2015
parent reply "Gan" <avisaria me.com> writes:
On Friday, 6 February 2015 at 00:24:54 UTC, Adam D. Ruppe wrote:
 On Friday, 6 February 2015 at 00:15:15 UTC, Gan wrote:
 		ubyte[] buf = new ubyte[](0);
This is your problem: receive fills a preexisting buffer, and you allocated zero bytes for it to fill, so it can't give you anything. Give it a bigger buffer, I like to use 4096, and it will work better.
Will there ever be a message bigger than 4096 bytes?
Feb 05 2015
parent reply "Gan" <avisaria me.com> writes:
On Friday, 6 February 2015 at 00:28:00 UTC, Gan wrote:
 On Friday, 6 February 2015 at 00:24:54 UTC, Adam D. Ruppe wrote:
 On Friday, 6 February 2015 at 00:15:15 UTC, Gan wrote:
 		ubyte[] buf = new ubyte[](0);
This is your problem: receive fills a preexisting buffer, and you allocated zero bytes for it to fill, so it can't give you anything. Give it a bigger buffer, I like to use 4096, and it will work better.
Will there ever be a message bigger than 4096 bytes?
Or am I misunderstanding the receive function? Does it send whole messages or just message chunks?
Feb 05 2015
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 6 February 2015 at 00:31:37 UTC, Gan wrote:
 Or am I misunderstanding the receive function? Does it send 
 whole messages or just message chunks?
It sends as much as it can when you call it. So if there's only 12 bytes available when you send it with a 4096 buffer, it will fill the first twelve bytes (and return 12) so you can slice it buffer[0 .. returnedValue] to get the data. If there's more available than the buffer will hold, that data will be held on to until next time you call receive. If 5000 bytes come off the network, it will return 4096 the first time, then next time through the loop, it will return the remaining 904.
Feb 05 2015
parent reply "Gan" <avisaria me.com> writes:
On Friday, 6 February 2015 at 00:35:12 UTC, Adam D. Ruppe wrote:
 On Friday, 6 February 2015 at 00:31:37 UTC, Gan wrote:
 Or am I misunderstanding the receive function? Does it send 
 whole messages or just message chunks?
It sends as much as it can when you call it. So if there's only 12 bytes available when you send it with a 4096 buffer, it will fill the first twelve bytes (and return 12) so you can slice it buffer[0 .. returnedValue] to get the data. If there's more available than the buffer will hold, that data will be held on to until next time you call receive. If 5000 bytes come off the network, it will return 4096 the first time, then next time through the loop, it will return the remaining 904.
How can you distinguish between different packets that get sent? Won't they all be merged to a giant blob of data?
Feb 05 2015
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 6 February 2015 at 00:50:43 UTC, Gan wrote:
 How can you distinguish between different packets that get 
 sent? Won't they all be merged to a giant blob of data?
Yeah, that's normal in TCP though, because it is a stream oriented protocol. You could add stuff to your data indicating message length though.
Feb 05 2015
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On 2/6/2015 9:50 AM, Gan wrote:
 On Friday, 6 February 2015 at 00:35:12 UTC, Adam D. Ruppe wrote:
 On Friday, 6 February 2015 at 00:31:37 UTC, Gan wrote:
 Or am I misunderstanding the receive function? Does it send whole
 messages or just message chunks?
It sends as much as it can when you call it. So if there's only 12 bytes available when you send it with a 4096 buffer, it will fill the first twelve bytes (and return 12) so you can slice it buffer[0 .. returnedValue] to get the data. If there's more available than the buffer will hold, that data will be held on to until next time you call receive. If 5000 bytes come off the network, it will return 4096 the first time, then next time through the loop, it will return the remaining 904.
How can you distinguish between different packets that get sent? Won't they all be merged to a giant blob of data?
You need to give each of your packets a header. At a minimum you'll want a message ID and message length. When a message comes in, you use the length field to determine where one packet ends and the next one begins.
Feb 05 2015
parent reply "Gan" <avisaria me.com> writes:
On Friday, 6 February 2015 at 01:36:17 UTC, Mike Parker wrote:
 On 2/6/2015 9:50 AM, Gan wrote:
 On Friday, 6 February 2015 at 00:35:12 UTC, Adam D. Ruppe 
 wrote:
 On Friday, 6 February 2015 at 00:31:37 UTC, Gan wrote:
 Or am I misunderstanding the receive function? Does it send 
 whole
 messages or just message chunks?
It sends as much as it can when you call it. So if there's only 12 bytes available when you send it with a 4096 buffer, it will fill the first twelve bytes (and return 12) so you can slice it buffer[0 .. returnedValue] to get the data. If there's more available than the buffer will hold, that data will be held on to until next time you call receive. If 5000 bytes come off the network, it will return 4096 the first time, then next time through the loop, it will return the remaining 904.
How can you distinguish between different packets that get sent? Won't they all be merged to a giant blob of data?
You need to give each of your packets a header. At a minimum you'll want a message ID and message length. When a message comes in, you use the length field to determine where one packet ends and the next one begins.
Oh sweet. Though if one message length is off by even 1 byte, then all future messages get corrupted?
Feb 05 2015
next sibling parent Andre Kostur <andre kostur.net> writes:
On 2015-02-05, 8:17 PM, Gan wrote:
 On Friday, 6 February 2015 at 01:36:17 UTC, Mike Parker wrote:
 On 2/6/2015 9:50 AM, Gan wrote:
 On Friday, 6 February 2015 at 00:35:12 UTC, Adam D. Ruppe wrote:
 On Friday, 6 February 2015 at 00:31:37 UTC, Gan wrote:
 Or am I misunderstanding the receive function? Does it send whole
 messages or just message chunks?
It sends as much as it can when you call it. So if there's only 12 bytes available when you send it with a 4096 buffer, it will fill the first twelve bytes (and return 12) so you can slice it buffer[0 .. returnedValue] to get the data. If there's more available than the buffer will hold, that data will be held on to until next time you call receive. If 5000 bytes come off the network, it will return 4096 the first time, then next time through the loop, it will return the remaining 904.
How can you distinguish between different packets that get sent? Won't they all be merged to a giant blob of data?
You need to give each of your packets a header. At a minimum you'll want a message ID and message length. When a message comes in, you use the length field to determine where one packet ends and the next one begins.
Oh sweet. Though if one message length is off by even 1 byte, then all future messages get corrupted?
Yep. You're using a reliable stream-based protocol. If you want discrete messages, you can use UDP. Though it is an unreliable packet-oriented protocol. Don't foul up your message lengths....
Feb 05 2015
prev sibling parent FG <home fgda.pl> writes:
On 2015-02-06 at 05:17, Gan wrote:
 Oh sweet. Though if one message length is off by even 1 byte, then all future
messages get corrupted?
Yes, but you can easily detect that by adding a magic number and packet checksum to the header.
Feb 06 2015