Reputation: 1467
edit
40+ views, and only one is able to help, isn't that question worth the upvote ? ;)
/edit
again I've some issues with socket programming in c#.
I've set up a little server with selfmade console ( richTextBox ) and it's listening for multiple connections.
well everything works fine except that if i close one of the connected clients, the programm will give me an async error and on the console it continuously writes a blank message from the client ( event:ClientReceivedHandler )
so can anyone help me finding the problem ??
my code :
SERVER - Form1.cs :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
namespace GameServer {
public partial class Form1 : Form {
// ### MAIN
public bool serverRunning = false;
public int serverListenPort = 6666;
static Listener l;
public Form1() {
InitializeComponent();
l = new Listener( serverListenPort );
l.SocketAccepted += new Listener.SocketAcceptedHandler( l_SocketAccepted );
}
void l_SocketAccepted( Socket e ) {
Client client = new Client( e );
client.Received += new Client.ClientReceivedHandler( client_Received );
client.Disconnected += new Client.ClientDisconnectedHandler( client_Disconnected );
Invoke( ( MethodInvoker )delegate {
dataGridViewConnections.Rows.Add( client.ID, client.EndPoint.ToString() );
consoleWrite( DateTime.Now + " - " + client.EndPoint + " connected to server.\n\n", Color.Lime );
} );
}
void client_Received( Client sender, byte[] data ) {
Invoke( ( MethodInvoker )delegate {
consoleWrite( DateTime.Now + "-" + sender.EndPoint + " :\n" + Encoding.Default.GetString( data ) + "\n\n", Color.White );;
} );
}
void client_Disconnected( Client sender ) {
Invoke( ( MethodInvoker )delegate {
for( int i = 0; i < dataGridViewConnections.Rows.Count; i++ ) {
if( dataGridViewConnections.Rows[i].Cells[0].Value.ToString() == sender.ID.ToString() ) {
dataGridViewConnections.Rows.RemoveAt( i );
consoleWrite( DateTime.Now + " - " + sender.EndPoint + " disconnected from server.\n\n", Color.OrangeRed );
break;
}
}
} );
}
private void checkBox1_Click(object sender, EventArgs e) {
checkBox1.Enabled = false;
if( !serverRunning ) {
consoleWrite( DateTime.Now + " " + markerSystem + "start\n", Color.White );
ServerStart();
checkBox1.Text = "Stop";
} else {
consoleWrite( DateTime.Now + " " + markerSystem + "stop\n", Color.White );
ServerStop();
checkBox1.Text = "Start";
}
checkBox1.Enabled = true;
}
private void ServerStart() {
if( !serverRunning ) {
consoleWrite( "* Starting server . . .\n", Color.Orange );
// Start Server
l.Start();
serverRunning = true;
consoleWrite( "* Server started !\n", Color.Lime );
consoleWrite("Listening on port " + serverListenPort + ".\n\n", Color.White );
} else {
consoleWrite( "* ERROR: Server already started !\n\n", Color.Red );
}
}
private void ServerStop() {
if( serverRunning ) {
consoleWrite( "* Stopping server . . .\n", Color.Orange );
// Stop Server
l.Stop();
serverRunning = false;
consoleWrite( "* Server stopped !\n\n", Color.Lime );
} else {
consoleWrite( "* ERROR: Server already stopped !\n\n", Color.Red );
}
}
private string markerSystem = "@System -> ";
private string marker = "-> ";
private void consoleWrite( string text, Color color ) {
consoleText.SelectionStart = consoleText.Text.Length;
consoleText.SelectionLength = 0;
consoleText.SelectionColor = color;
consoleText.AppendText( text );
}
}
}
SERVER - Listener.cs :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace GameServer {
class Listener {
Socket s;
public bool Listening {
get;
private set;
}
public int Port {
get;
private set;
}
public Listener( int port ) {
Port = port;
s = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
}
public void Start() {
if( Listening ) {
return;
}
s.Bind( new IPEndPoint( 0, Port ) );
s.Listen(0);
s.BeginAccept( callback, null );
Listening = true;
}
public void Stop() {
if( !Listening ) {
return;
}
s.Close();
s.Dispose();
s = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
}
void callback( IAsyncResult ar ) {
try {
Socket s = this.s.EndAccept( ar );
if( SocketAccepted != null ) {
SocketAccepted( s );
}
this.s.BeginAccept( callback, null );
} catch( Exception ex ) {
MessageBox.Show( ex.Message );
}
}
public delegate void SocketAcceptedHandler( Socket e );
public event SocketAcceptedHandler SocketAccepted;
}
}
SERVER - Client.cs :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace GameServer {
class Client {
public string ID {
get;
private set;
}
public IPEndPoint EndPoint {
get;
private set;
}
Socket sck;
public Client( Socket accepted ) {
sck = accepted;
ID = Guid.NewGuid().ToString();
EndPoint = ( IPEndPoint )sck.RemoteEndPoint;
sck.BeginReceive( new byte[] { 0 }, 0, 0, 0, callback, null );
}
void callback( IAsyncResult ar ) {
try {
sck.EndReceive( ar );
byte[] buf = new byte[8192];
int rec = sck.Receive( buf, buf.Length, 0 );
if( rec < buf.Length ) {
Array.Resize<byte>( ref buf, rec );
}
if( Received != null ) {
Received( this, buf );
}
sck.BeginReceive( new byte[] { 0 }, 0, 0, 0, callback, null );
} catch( Exception ex ) {
MessageBox.Show( ex.Message );
Close();
if( Disconnected != null ) {
Disconnected( this );
}
}
}
public void Close() {
sck.Close();
sck.Dispose();
}
public delegate void ClientReceivedHandler( Client sender, byte[] data );
public delegate void ClientDisconnectedHandler( Client sender );
public event ClientReceivedHandler Received;
public event ClientDisconnectedHandler Disconnected;
}
}
CLIENT - Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace GameClient {
public partial class Form1:Form {
Socket sck;
public Form1() {
InitializeComponent();
sck = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
sck.Connect( "127.0.0.1", 6666 );
}
private void button1_Click( object sender, EventArgs e ) {
int s = sck.Send( Encoding.Default.GetBytes( textBox1.Text ) );
if( s > 0 ) {
textBox1.Text = "";
}
}
private void button2_Click( object sender, EventArgs e ) {
sck.Close();
sck.Dispose();
}
}
}
i would be really really glad to make this server stable so i can start implementing multiplayer game server logics :D
thanks everyone who can help me out.
P.S. If anyone needs to see the problem in action, i can upload the VS project files or the .exe files of server and client.
UPDATE :
the first problem ( async error ) appears in the Listener.cs file in the try-catch. the messagebox in the catch section gives this text :
"IAsyncResult object was not returned from the corresponding asynchronous method. parameter : asyncResult"
this comes when the "ServerStop()" method is called.
the second problem is anywhere in the client_Received() method in the SERVER-Form1.cs.
it seems that it continuously receives blank data, so it outputs a blank message in the console/richTextBox
I'm not familiar with the socket-logic in c#, so i can't figure out where in the code the locig-error happens.
hope that anyone has found it.
EDIT :
project files in zip file http://ace-acid.no-ip.org/GameServer/
(c)
Upvotes: 1
Views: 2205
Reputation: 5571
the first problem ( async error ) appears in the Listener.cs file in the try-catch. the messagebox in the catch section gives this text :
"IAsyncResult object was not returned from the corresponding asynchronous method. parameter : asyncResult"
In Listener.cs - GameServer, This error may be safely ignored. I believe that ignoring the error will not cause problems during starting / stopping the socket. The problem is that you forgot to add Listening = false;
at the end of Stop()
so that the application can call Start()
once again to start the socket. Otherwise, the socket will never start if stopped.
Example
public void Stop()
{
if (!Listening)
{
return;
}
s.Close();
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Listening = false; //Set Listening to False to start the socket again
}
Though setting Listening = false;
will resolve restarting the socket, it will not stop you from getting the exception you mentioned above because the exception does not depend on Listening
.
I've tried fixing this but it always told me that it was impossible to access the disposed object s(socket)
so that I think that the exception is based on this line s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
.
The exception can be safely ignored anyways, I've ignored it and it worked perfectly. To ignore it, simply create a try/catch
block getting the exception, if the exception message contained asyncResult
then, ignore popping out a box with the exception.
Example
void callback(IAsyncResult ar)
{
try
{
Socket s = this.s.EndAccept(ar);
if (SocketAccepted != null)
{
SocketAccepted(s);
}
this.s.BeginAccept(callback, null);
}
catch (Exception ex)
{
if (!ex.Message.Contains("asyncResult")) //Proceed only if the exception does not contain asyncResult
{
MessageBox.Show(ex.Message);
}
}
}
it seems that it continuously receives blank data, so it outputs a blank message in the console/richTextBox
Yes, it will always receive a blank data since there's a connection. You can see this in the following screenshot
To solve this, you'll first need to check that the returned string using Encoding
from the byte[] data
is not blank. Then, you can write a new line in the console/richtextbox
Example
In Form1.cs - GameServer
Replace client_Received(Client sender, byte[] data)
with the following code
void client_Received(Client sender, byte[] data)
{
if (Encoding.Default.GetString(data) != "") //Proceed only if data is not blank
{
Invoke((MethodInvoker)delegate
{
consoleWrite(DateTime.Now + "-" + sender.EndPoint + " :\n" + Encoding.Default.GetString(data) + "\n\n", Color.White); ;
});
}
}
}
After applying the fix, here's the output
There's another problem that you might have forgot to mention, under Connections
tab, the list is never cleared even after the server disconnects. Simply call dataGridViewConnections.Rows.Clear();
to clear the connections list when ServerStop()
is called.
Example
In Form1.cs - GameServer
Replace ServerStop()
with the following code
private void ServerStop()
{
if (serverRunning)
{
consoleWrite("* Stopping server . . .\n", Color.Orange);
l.Stop();
serverRunning = false;
consoleWrite("* Server stopped !\n\n", Color.Lime);
dataGridViewConnections.Rows.Clear(); // Clear connections
}
else
{
consoleWrite("* ERROR: Server already stopped !\n\n", Color.Red);
}
}
That's all I could detect at the moment, I'll keep you updated if I find anything relevant.
Alternatively, you can find the project files that belongs to the namespace GameServer
here
Thanks,
I hope you find this helpful :)
Upvotes: 1