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
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
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
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...
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
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.
Was ist bei Application.ThreadException rausgekommen?
Die Exception kann ich nicht abfangen ! Es kommt die FehlerMessagebox die ich als Bild angehängt habe.
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...