1

編集

40以上のビュー、そして1つだけが助けることができます、その質問は賛成する価値がありませんか?;)

/編集

繰り返しますが、C#でのソケットプログラミングに問題があります。

自作のコンソール(richTextBox)を備えた小さなサーバーをセットアップし、複数の接続をリッスンしています。

接続されたクライアントの1つを閉じると、プログラムが非同期エラーを表示し、コンソールでクライアントからの空白のメッセージを継続的に書き込むことを除いて、すべてが正常に機能します(event:ClientReceivedHandler)

だから誰かが私が問題を見つけるのを手伝ってくれる?

私のコード:

サーバー-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 );
    }
}
}

サーバー-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;
    }
}

サーバー-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;
    }
}

クライアント-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();
        }
    }
}

マルチプレイヤーゲームサーバーロジックの実装を開始できるように、このサーバーを安定させて本当にうれしいです:D

私を助けてくれるすべての人に感謝します。

PS誰かが実際の問題を確認する必要がある場合は、VSプロジェクトファイルまたはサーバーとクライアントの.exeファイルをアップロードできます。

アップデート :

最初の問題(非同期エラー)は、try-catchのListener.csファイルに表示されます。catchセクションのメッセージボックスに次のテキストが表示されます。

「IAsyncResultオブジェクトが対応する非同期メソッドから返されませんでした。パラメーター:asyncResult」

これは、「ServerStop()」メソッドが呼び出されたときに発生します。

2番目の問題は、SERVER-Form1.csのclient_Received()メソッドのどこかにあります。

空白のデータを継続的に受信しているように見えるため、console/richTextBoxに空白のメッセージを出力します

私はc#のsocket-logicに精通していないため、コードのどこでlocig-errorが発生するのかわかりません。

誰かがそれを見つけたことを願っています。

編集 :

zipファイル内のプロジェクトファイル http://ace-acid.no-ip.org/GameServer/

(c)

4

1 に答える 1

1

最初の問題(非同期エラー)は、try-catchのListener.csファイルに表示されます。catchセクションのメッセージボックスに次のテキストが表示されます。

「IAsyncResultオブジェクトが対応する非同期メソッドから返されませんでした。パラメーター:asyncResult」

Listener.cs-GameServerでは、このエラーは安全に無視できます。エラーを無視しても、ソケットの起動/停止時に問題が発生することはないと思います。問題は、アプリケーションがソケットを開始するためにもう一度呼び出すことができるようListening = false;に、最後に追加するのを忘れたことです。そうしないと、ソケットが停止しても起動しません。Stop()Start()

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
}

設定Listening = false;するとソケットの再起動は解決されますが、例外はに依存しないため、上記の例外の発生を停止することはありませんListening

これを修正しようとしましたが、破棄されたオブジェクトにアクセスできないと常に言われていたs(socket)ため、例外はこの行に基づいていると思いますs = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

例外はとにかく安全に無視できます、私はそれを無視しました、そしてそれは完全に働きました。try/catchそれを無視するには、例外を取得するブロックを作成するだけです。例外メッセージが含まれている場合は、例外asyncResultのあるボックスのポップアウトを無視します。

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);
           }
      }
}

空白のデータを継続的に受信しているように見えるため、console/richTextBoxに空白のメッセージを出力します

はい、接続があるため、常に空白のデータを受け取ります。これは次のスクリーンショットで確認できます

Picrofoコンソールから送信された空白のデータ

Encodingこれを解決するには、まず、fromを使用して返された文字列byte[] dataが空白でないことを確認する必要があります。次に、コンソール/リッチテキストボックスに新しい行を書き込むことができます

Form1.csの場合-GameServer

client_Received(Client sender, byte[] data)次のコードに置き換えます

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); ;
            });
          }
     }
}

修正を適用した後、これが出力です

空白のデータはもうありません!

言及するのを忘れたかもしれない別の問題がありConnectionsます。タブの下で、サーバーが切断された後でもリストがクリアされることはありません。dataGridViewConnections.Rows.Clear();が呼び出されたときに接続リストをクリアするには、を呼び出すだけServerStop()です。

Form1.csの場合-GameServer

ServerStop()次のコードに置き換えます

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);
     }
 }

現時点で検出できるのはこれだけです。関連するものが見つかった場合は、最新情報をお知らせします。

または、名前空間に属するプロジェクトファイルをここで見つけることができますGameServer

ありがとう、
これがお役に立てば幸いです:)

于 2012-10-28T19:27:37.907 に答える