digitalmars.D.learn - Trying to make a TCP server, client connects and disconnects
- Gan (111/111) Feb 05 2015 I managed to get the client to connect but immediately on the
- Adam D. Ruppe (6/7) Feb 05 2015 This is your problem: receive fills a preexisting buffer, and you
- Gan (2/9) Feb 05 2015 Will there ever be a message bigger than 4096 bytes?
- Gan (3/14) Feb 05 2015 Or am I misunderstanding the receive function? Does it send whole
- Adam D. Ruppe (9/11) Feb 05 2015 It sends as much as it can when you call it. So if there's only
- Gan (3/15) Feb 05 2015 How can you distinguish between different packets that get sent?
- Adam D. Ruppe (4/6) Feb 05 2015 Yeah, that's normal in TCP though, because it is a stream
- Mike Parker (4/20) Feb 05 2015 You need to give each of your packets a header. At a minimum you'll want...
- Gan (3/34) Feb 05 2015 Oh sweet. Though if one message length is off by even 1 byte,
- Andre Kostur (4/30) Feb 05 2015 Yep. You're using a reliable stream-based protocol. If you want
- FG (2/3) Feb 06 2015 Yes, but you can easily detect that by adding a magic number and packet ...
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
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
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:Will there ever be a message bigger than 4096 bytes?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
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:Or am I misunderstanding the receive function? Does it send whole messages or just message chunks?On Friday, 6 February 2015 at 00:15:15 UTC, Gan wrote:Will there ever be a message bigger than 4096 bytes?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
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
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:How can you distinguish between different packets that get sent? Won't they all be merged to a giant blob of data?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
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
On 2/6/2015 9:50 AM, Gan wrote:On Friday, 6 February 2015 at 00:35:12 UTC, Adam D. Ruppe wrote: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.On Friday, 6 February 2015 at 00:31:37 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?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
On Friday, 6 February 2015 at 01:36:17 UTC, Mike Parker wrote:On 2/6/2015 9:50 AM, Gan wrote:Oh sweet. Though if one message length is off by even 1 byte, then all future messages get corrupted?On Friday, 6 February 2015 at 00:35:12 UTC, Adam D. Ruppe wrote: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.On Friday, 6 February 2015 at 00:31:37 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?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
On 2015-02-05, 8:17 PM, Gan wrote:On Friday, 6 February 2015 at 01:36:17 UTC, Mike Parker wrote: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....On 2/6/2015 9:50 AM, Gan wrote:Oh sweet. Though if one message length is off by even 1 byte, then all future messages get corrupted?On Friday, 6 February 2015 at 00:35:12 UTC, Adam D. Ruppe wrote: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.On Friday, 6 February 2015 at 00:31:37 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?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
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