Laden...

AsyncCallback Fehler ?

Erstellt von Soulfly vor 19 Jahren Letzter Beitrag vor 19 Jahren 3.399 Views
S
Soulfly Themenstarter:in
73 Beiträge seit 2004
vor 19 Jahren
AsyncCallback Fehler ?

Hi Leute

habe folgendes Problem:
Habe einen Server der mit einer AsyncCallback auf "empfangene Daten wartet".
Habe zwei Buttons einen der den Server startet -das funtzt ! Ich kann auch daten mit client austauschen.

und einen soll den Server beenden. Dort kommt aber eine Fehlermeldung:

Eine nicht behandelte Ausnahme des Typs 'System.Net.Sockets.SocketException' ist in system.dll aufgetreten.

Zusätzliche Informationen: Eine Anforderung zum Senden oder Empfangen von Daten wurde verhindert, da der Socket nicht verbunden ist und (beim Senden über einen Datagrammsocket mit einem sendto-Aufruf) keine Adresse angegeben wurde

Hier mal Programmausschnitte



public class cl_server
{
....
private Socket		  cl_soc_listener;			
private AsyncCallback cl_asy_Callback;
....



...
cl_asy_Callback = new AsyncCallback(this.OnConnectRequest);
cl_soc_listener.BeginAccept(cl_asy_Callback, cl_soc_listener);
...

wenn ich jetzt :


cl_soc_listener.Shutdown(SocketShutdown.Both);
cl_soc_listener.Close();

bei dem zweiten button schreibe kommt die oben genannte Fehlermeldung. auch wenn ich mit try und catch was versuche kommt trotzdem die Fehlermeldung.

Ich hoffe mir kann da einer weiterhelfen.

Gruß Soulfly

P
939 Beiträge seit 2003
vor 19 Jahren

Also ich sehe wie der Fehler entsteht. Wie man ihn verhindert oder abfängt, ist ne andere Geschichte.

Und zwar wird mit BeginAccept ein zweiter Thread gestartet, der am Port horcht. Wenn du jetzt im Main-Thread diesen Port schliesst, wird im Horch-Thread natürlich eine Exception geworfen.

Bloss wie kann man die abfangen? Oder wie kann man dem Horch-Thread sagen, dass er sich beenden soll? Wenn es eine WinForms-Anwendung ist, könntest du die Exception über das Application.ThreadException-Ereignis bekommen und so etwaige Exception-Dialoge unterdrücken (glaube ich). Wie äußert sich die Exception eigentlich?

Gruss
Pulpapex

S
Soulfly Themenstarter:in
73 Beiträge seit 2004
vor 19 Jahren

Ich habe mal die Fehler Messagebox angehängt und hier mal der komplette Quellecode:

Form.cs


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
using System.Net;
using System.Net.Sockets;


namespace server
{
	public class Form1 : System.Windows.Forms.Form
	{
		private System.Windows.Forms.Button m_btnServerStarten;
		private System.Windows.Forms.Button m_btnServerStoppen;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.ListBox m_lbEvents;
		private System.Windows.Forms.ComboBox m_cbIPAdressen;
		private System.Windows.Forms.TextBox m_intPort;
		private System.ComponentModel.Container components = null;

		public Form1()
		{
			InitializeComponent();

			myserver.cl_lb_events = m_lbEvents;		
		}	
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
	
		#endregion


		cl_server myserver =  new cl_server();
	

		[STAThread]

		

		
		static void Main() 
		{
		
			Application.Run(new Form1());
			
		 		
		}
		
		

		private void Form1_Load(object sender, System.EventArgs e)
		{
			m_lbEvents.Items.Clear();
			if(myserver.cl_ipar_LocalAddr!=null&&myserver.cl_ipar_LocalAddr.Length>0)
			{
				foreach( IPAddress tmpIP in myserver.cl_ipar_LocalAddr )
				{
					m_cbIPAdressen.Items.Add(tmpIP.ToString());
				}
			}
			else 
				m_cbIPAdressen.Items.Add("keine Gülitge IP");

		}

		private void m_btnServerStarten_Click(object sender, System.EventArgs e)
		{
			myserver.SetConfig(Convert.ToInt32(m_intPort.Text.ToString()),IPAddress.Parse(m_cbIPAdressen.SelectedItem.ToString()),10);
			myserver.connect();
			myserver.callback();
					
			myserver.printinfo();
		}


		private void Form1_Closed(object sender, System.EventArgs e)
		{

		}

		private void m_btnServerStoppen_Click(object sender, System.EventArgs e)
		{
			
			myserver.disconnect();
					
		}

	

		}
		

	}



und hier die Klasse
cl_server.cs:

using System; 
using System.Net;
using System.Net.Sockets;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
using System.Text;

namespace server
{
	/// <summary>
	/// Zusammendfassende Beschreibung für cl_server.
	/// </summary>
	public class cl_server
	{

		private int					cl_int_Port;					// Port der Verbindung
		private IPAddress	cl_ip_Address;				// IPAdresse des Servers
		private string			cl_str_HostName;			// Der durch DNS ermittelte Hostname
		private Socket			cl_soc_listener;			// Der Socket listerner
		private int					cl_int_MaxConn;			// Maximale Client(Verbindungsanzahl)
		private ArrayList		cl_arr_Clients = new ArrayList();				// Liste der Client Verbindungen
		public IPAddress []	cl_ipar_LocalAddr;
		private bool				cl_bo_IsOnline;				// Ob der server online ist
		private AsyncCallback cl_asy_Callback;
	
		

		 
		public ListBox			cl_lb_events;					// Eventsanzeige


		// Konstruktur 
		public cl_server()
		{
				cl_bo_IsOnline = false;
				cl_int_Port = 399;
				cl_ip_Address = IPAddress.Parse("127.0.0.1");
			try
			{
				
				// IP-Addresse über DNS Host Namen holen
				cl_str_HostName = Dns.GetHostName();
				IPHostEntry ipEntry = Dns.GetHostByName(cl_str_HostName);
				cl_ipar_LocalAddr = ipEntry.AddressList;
			}
			catch
			{}
		
	
		}

		// Settings
		public void SetConfig(int xPort, IPAddress xIpAddress , int xMaxClients)
		{
			cl_int_MaxConn = xMaxClients;
			cl_ip_Address = xIpAddress;
			cl_int_Port = xPort;
		}

		public void AddEvent(string Message)
		{
			DateTime now = DateTime.Now;
			if(cl_lb_events!=null)
				
                cl_lb_events.Items.Add(now.ToString("G") + ": " + Message + "");
		}

		
		public bool isOnline   
		{
			get 
			{
				return cl_bo_IsOnline; 
			}
		}

		public void printinfo()
		{
			AddEvent("Host: "+ cl_str_HostName);
			AddEvent("IP: " + cl_ip_Address.ToString());
			AddEvent("Port: " + cl_int_Port.ToString());
		}

		public void connect()
		{
			try
			{

				cl_soc_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
				cl_soc_listener.Bind( new IPEndPoint(cl_ip_Address,cl_int_Port));
				cl_soc_listener.Listen(cl_int_MaxConn);
				AddEvent("CONNECT");
				cl_bo_IsOnline = true;
			}
			catch
			{
				AddEvent("Fehler: Fehler beim Connecten");
				cl_bo_IsOnline = false;
			}
		}

		public  void callback()
		{
			cl_asy_Callback = new AsyncCallback(this.OnConnectRequest);

			cl_soc_listener.BeginAccept(cl_asy_Callback, cl_soc_listener);
		
		}

		public void disconnect()
		{

			if(cl_bo_IsOnline==true)
			{
			
				try{
					
					cl_soc_listener.Close(); // HIER DIE FEHLERMELDUNG
					AddEvent("SERVER OFFLINE");
				
					}
				catch
					{

					AddEvent("Fehler beim runterfahren");
				
					}
				
				
			}
		}

		public void OnConnectRequest(IAsyncResult ar)
		{
			Socket listener = (Socket) ar.AsyncState;
			NewConnection ( listener.EndAccept  ( ar ) );
			listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
		}

		public void NewConnection(Socket sockClient)
		{
			SocketChatClient client = new SocketChatClient(sockClient);
			cl_arr_Clients.Add(client);
			

			AddEvent("Client: " + client.Sock.RemoteEndPoint.ToString() + "  ist   online" );
            DateTime now = DateTime.Now;
			String strDateLine = "Willkommen " + now.ToString("G") + "\n\r";
			Byte[] byteDateLine = System.Text.Encoding.ASCII.GetBytes(strDateLine.ToCharArray() );
			client.Sock.Send ( byteDateLine, byteDateLine.Length, 0);
            client.SetupRecieveCallback(this);

		}
		public void OnRecievedData(IAsyncResult ar)
		{
			
			SocketChatClient client = (SocketChatClient)ar.AsyncState;
			Byte [] aryRet = client.GetReceivedData( ar );
			string sRecieved = Encoding.ASCII.GetString(aryRet);
				

			// If no data was recieved then the connection is probably dead
			if( aryRet.Length < 1 )
			{
				AddEvent("Client: " + client.Sock.RemoteEndPoint + " disconnected");
				client.Sock.Close();
				cl_arr_Clients.Remove( client );      				
				return;
			}


			AddEvent(client.Sock.RemoteEndPoint + ": "  + sRecieved);

			// Send the recieved data to all clients (including sender for echo)
			foreach( SocketChatClient clientSend in cl_arr_Clients )
			{
				try
				{
					
					clientSend.Sock.Send( aryRet );
				}
				catch
				{
					// If the send fails the close the connection
					Console.WriteLine( "Send to client {0} failed", client.Sock.RemoteEndPoint );
					clientSend.Sock.Close();
					cl_arr_Clients.Remove( client );
					return;
				}
			}
			client.SetupRecieveCallback( this );
		}


		



	}
	internal class SocketChatClient
	{
		private Socket m_sock;
		private byte[] m_byBuff = new byte[50];

		public SocketChatClient(Socket sock)
		{
			m_sock  = sock;
		}
		public Socket Sock
		{
			get
			{
				return m_sock; 
			}
		}
		public void SetupRecieveCallback(cl_server app)
		{
			try
			{
				AsyncCallback recieveData = new AsyncCallback(app.OnRecievedData);
				m_sock.BeginReceive(m_byBuff,0,m_byBuff.Length,SocketFlags.None,recieveData,this);
			}
			catch
			{
				MessageBox.Show("Fehler bei Empfangs Routine","Fehler");
			}
		}
		
		public byte [] GetReceivedData(IAsyncResult ar )
		{
			int nBytesRec = 0;
			try
			{
				nBytesRec = m_sock.EndReceive( ar );
			}
			catch{}
			byte [] byReturn = new byte[nBytesRec];
			Array.Copy( m_byBuff , byReturn , nBytesRec );
			return byReturn;

		}
	}
	
}

Ich hoffe nicht das das jetzt zu unübersichtlich geworden ist.

Gruß Soulfly

4.221 Beiträge seit 2005
vor 19 Jahren

cl_soc_listener

dieser bleibt offen weil du den Asynch nicht beendet hast...

Stichwort: EndAccept

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

S
Soulfly Themenstarter:in
73 Beiträge seit 2004
vor 19 Jahren

Mmhh - aber das Problem ist doch das EndAccept als Parameter IAsyncResult benötigt und ich bekomme doch nur ein Result wenn ich eine Socket Anfrage habe.

in der


public void OnConnectRequest(IAsyncResult ar)
		{
			Socket listener = (Socket) ar.AsyncState;
			NewConnection ( listener.EndAccept  ( ar ) );
			listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
		}

methode habe ich ja wenn eine Anfrage kommt den ar und kann somit den neuen Client mit "verknüpfen" .

Kannst du mir bitte erklären wo und wie ich EndAccept in der Disconnect Routine einbauen kann. Ich habe leider keine Ahnung.

Gruß Soulfly

P
939 Beiträge seit 2003
vor 19 Jahren

EndAccept bringt meiner Meinung nach auch nichts. Die Methode würde auf die Beendigung des "Listener"-Threads warten.
Der blockiert jedoch für immer und ewig, weil er auf den Aufbau einer Verbindung wartet.

Was ist bei Application.ThreadException rausgekommen?

Gruss
Pulpapex

PS: BeginAccept gibt das IAsyncResult-Objekt zurück, das für den Aufruf von EndAccept benötigt wird.
Das bringt nur wie gesagt nichts.

S
Soulfly Themenstarter:in
73 Beiträge seit 2004
vor 19 Jahren

Was ist bei Application.ThreadException rausgekommen?

Die Exception kann ich nicht abfangen ! Es kommt die FehlerMessagebox die ich als Bild angehängt habe.

4.221 Beiträge seit 2005
vor 19 Jahren

Also ich würde auf den TcpListener ausweichen...

Zudem Asynchrone Vorgänge nur starten wenn Du sicher bist, dass du diese auch beenden kannst....

Den Accept würde ich in einem eigenen Thread laufen lassen....

So in etwa wiefolgt: (ist nich vollständig getestet .... aber so in diese Richtung)


		private bool _Shutdown=false;
		private Thread _ThreadListen;
		private GotConnectionDelegate _ConnDel;
		private void GotConnection(Socket pSock)
		{
			//mach was damit :-)
		}


		private void StartListenInternal()
		{
			if (_ConnDel==null)
			{
				_ConnDel=new GotConnectionDelegate(this.GotConnection);
			}
			IPAddress ipAddress = Dns.Resolve("localhost").AddressList[0];
			TcpListener tcpListener =  new TcpListener(ipAddress, 8085);
			tcpListener.Start();

			while(!this._Shutdown)
			{
				if (tcpListener.Pending())
				{
					System.Diagnostics.Debug.WriteLine("Accepting Connection");
					Socket sockIn=tcpListener.AcceptSocket();
					this.Invoke(this._ConnDel,new object[]{sockIn});
				}
				else
				{
					System.Diagnostics.Debug.WriteLine("No connection pending");
					Thread.Sleep(100);
				}
			}
			System.Diagnostics.Debug.WriteLine("Stopping Listen-Mode");
			tcpListener.Stop();
			tcpListener=null;
			System.Diagnostics.Debug.WriteLine("Listen-Mode stopped");
		}

		private void btnListen_Click(object sender, System.EventArgs e)
		{
			if (this._ThreadListen==null)
			{
				this.btnListen.Enabled=false;
				this._Shutdown=false;
				this._ThreadListen=new Thread(new ThreadStart(this.StartListenInternal));
				this._ThreadListen.Name="TcpListener on Port xy";
				this._ThreadListen.Start();
			}
		}

		private void btnShutdown_Click(object sender, System.EventArgs e)
		{
			this._Shutdown=true;
			//warte bis der Listen-Thread sich verabschiedet
			this._ThreadListen.Join();
			this._ThreadListen=null;
			this.btnListen.Enabled=true;
		}

		private delegate void GotConnectionDelegate(Socket pSock);


Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...