Forum: PC-Programmierung TCPserver in C#


von Martin (Gast)


Lesenswert?

Hallo,

ich versuche mich an einem TCP-Server in C#, der Daten von einem 
TCP-Client in C empfängt. Das Problem ist, dass der Server nach einer 
willkürlichen Anzahl von Empfangvorgängen nichts mehr empfängt, der 
Client jedoch weiterarbeitet.
1
 mythread = new Thread(new ThreadStart(listen_tcp));
2
 mythread.start();
3
4
 private void listen_tcp()
5
        {
6
            string tmp = null;
7
            IPAddress ipAddress = IPAddress.Any;
8
            listener = new TcpListener(ipAddress, 12345);
9
            listener.Start();
10
            Console.WriteLine("Server is running");
11
            Console.WriteLine("Listening on port " + 12345);
12
            Console.WriteLine("Waiting for connections...");       
13
            s = listener.AcceptSocket();
14
            Console.WriteLine("Connection accepted from " + s.RemoteEndPoint);
15
            while (s.Connected == true) 
16
            {
17
18
                byte[] b = new byte[100];
19
                char[] c = new char[100];
20
                int k = s.Receive(b);
21
                //Console.WriteLine("Received:");
22
                for (int i = 0; i < k; i++)
23
                {
24
                    Console.Write(Convert.ToChar(b[i]));
25
                    c[i] = Convert.ToChar(b[i]);
26
                }
27
                tmp = new string(c);
28
                convert_vs(tmp);
29
                tmp = null;
30
                ASCIIEncoding enc = new ASCIIEncoding();
31
                s.Send(enc.GetBytes("Server responded"));
32
                //Console.WriteLine("\nSent Response");
33
                if (s.Connected == false) s.Close();
34
                if (shut_down == true)
35
                {
36
                    s.Close();
37
                    mythread.Abort();
38
                    Console.WriteLine("Mythread wurde beendet");
39
                }
40
41
            }
42
        }

Teilweise kommt die Meldung: Der Thread xx hat mit Fehlercode 0x00 
geendet.
Kennt jemand das Problem bzw. hat sogar eine Lösung dafür?
Viele Grüße,
Martin

von Peter II (Gast)


Lesenswert?

Martin schrieb:
> Der Thread xx hat mit Fehlercode 0x00 geendet.
man könnte ja auch mal eine Fehlerbehandlung einbauen.

Try Catch ist das stichwort.

von Marcus B. (raketenfred)


Lesenswert?

Martin schrieb:
> Teilweise kommt die Meldung: Der Thread xx hat mit Fehlercode 0x00
> geendet.

.Net wirft eigentlich aussagen kräftigere Fehlermeldungen.

Ansonsten umschließe den Bereich mal mit try-catch und lass die 
Fehlermeldung entweder protokollieren oder aufpoppen.

Dein Threading arbeitet aber etwas komisch

Generell gibt es einen Thread, der den Port offen hält, und wenn dann 
sich jemand auf den Port verbindet, leitet der erste Thread, das ganze 
weiter und spawnt einen neuen Thread, der sich nur um diese eine 
Verbindung kümmert.

Wenn das C-Programm irgendwann die Verbindung schließt, dann endet auch 
dein Thread, d.h. es kann sich noch nichtmals neustarten.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Martin schrieb:
> s = listener.AcceptSocket();

An der stelle musst du/solltest du einen eigenen Thread aufmachen.

Martin schrieb:
> mythread.Abort();

Was soll das? Ein einfaches break reicht völlig aus.

Martin schrieb:
> if (s.Connected == false) s.Close();

Das schließen sollte immer hinter dem while block passieren und nicht 
nur manchmal wenn die Verbindung weshalb auch immer nicht mehr connected 
ist...

Martin schrieb:
> if (shut_down == true)

gehört in die while Bedingung.

Martin schrieb:
> Kennt jemand das Problem bzw. hat sogar eine Lösung dafür?

Überdenke deinen Programmfluss da geht einiges durcheinander...

von Martin (Gast)


Lesenswert?

Danke für die ganzen Hinweise, ich bin in C# leider ziemlicher 
Anfänger... ich habe versucht etwas davon umzusetzen, es klappt immer 
noch nicht.
1
namespace TCPServer
2
{
3
    public partial class Form1 : Form
4
    {
5
        public Socket s;
6
        public Thread mythread = null;
7
        public TcpListener listener = null;
8
        public Thread cl_thread;
9
        
10
        public Form1()
11
        {
12
            InitializeComponent();
13
            mythread = new Thread(new ThreadStart(listen_tcp));
14
            mythread.Start();
15
        }
16
17
        private void Form1_Load(object sender, EventArgs e)
18
        {
19
20
        }
21
22
        private void client_thread()
23
        {
24
            Console.WriteLine("Test " + s.RemoteEndPoint);
25
            string tmp = null;
26
            while (s.Connected == true)
27
            {
28
                byte[] b = new byte[100];
29
                char[] c = new char[100];
30
                int k = s.Receive(b);
31
                //Console.WriteLine("Received:");
32
                for (int i = 0; i < k; i++)
33
                {
34
                    Console.Write(Convert.ToChar(b[i]));
35
                    c[i] = Convert.ToChar(b[i]);
36
                }
37
                tmp = new string(c);
38
                //convert_vs(tmp);
39
                tmp = null;
40
                ASCIIEncoding enc = new ASCIIEncoding();
41
            }
42
            Console.WriteLine("Verbindung beendet");
43
        }
44
45
        private void listen_tcp()
46
        {      
47
            IPAddress ipAddress = IPAddress.Any;
48
            listener = new TcpListener(ipAddress, 12345);
49
            listener.Start();
50
            Console.WriteLine("Server is running");
51
            Console.WriteLine("Listening on port " + 12345);
52
            Console.WriteLine("Waiting for connections...");
53
            while (true)
54
            {
55
                s = listener.AcceptSocket();
56
                cl_thread = new Thread(new ThreadStart(client_thread));
57
                cl_thread.Start();
58
            }
59
           
60
        } 
61
    }
62
}
Nach einer Weile kommt nichts mehr beim Server an. Beende ich dann das 
Client Programm und starte es neu, kann ich mich laut Client erfolgreich 
verbinden, die Bestätigung im Server Programm bleibt aber aus.

von Peter II (Gast)


Lesenswert?

du muss deinen Thread auch den socket übergeben! du machst es jetzt mit 
einen Globalen variabel in der Klasse das geht aber nciht, weil du nur 
eine Variabel hast aber jeder client braucht seinen eigenen socket.

Ich denke du solltest etwas einfacher anfangen, lerne erstmal die 
Sprache bevor du mit Client-Server verbindungen anfängst.

von Olek (Gast)


Lesenswert?

Tu Dir und mir einen Gefallen und kommentiere mal jede Zeile mit dem was 
du da eigentlich machst. Es ist nicht besonders einfach deinem 
Gedankengang da zu folgen.

Um so früher Du damit anfängst um so besser, den am Ende machst Du das 
dann doch nicht... kenne ich leider von mir all zu gut :)

von Martin (Gast)


Lesenswert?

1
public partial class Form1 : Form
2
    {
3
        public Thread mythread = null;
4
        public TcpListener listener = null;
5
        public Thread cl_thread;
6
        
7
        public Form1()
8
        {
9
            InitializeComponent();
10
            mythread = new Thread(new ThreadStart(listen_tcp));
11
            mythread.Start();
12
        }
13
14
        private void Form1_Load(object sender, EventArgs e)
15
        {
16
17
        }
18
19
        private void client_thread(Socket s)
20
        {
21
            Console.WriteLine("Test " + s.RemoteEndPoint);
22
            string tmp = null;
23
            while (s.Connected == true)
24
            {
25
                byte[] b = new byte[100];
26
                char[] c = new char[100];
27
                int k = s.Receive(b);
28
                //Console.WriteLine("Received:");
29
                for (int i = 0; i < k; i++)
30
                {
31
                    Console.Write(Convert.ToChar(b[i]));
32
                    c[i] = Convert.ToChar(b[i]);
33
                }
34
                tmp = new string(c);
35
                //convert_vs(tmp);
36
                tmp = null;
37
                ASCIIEncoding enc = new ASCIIEncoding();
38
            }
39
            Console.WriteLine("Verbindung beendet");
40
        }
41
42
        private void listen_tcp()
43
        {      
44
            IPAddress ipAddress = IPAddress.Any;
45
            listener = new TcpListener(ipAddress, 12345);
46
            listener.Start();
47
            Console.WriteLine("Server is running");
48
            Console.WriteLine("Listening on port " + 12345);
49
            Console.WriteLine("Waiting for connections...");
50
            while (true)
51
            {
52
                Socket cl_socket = listener.AcceptSocket();
53
                cl_thread = new Thread(new ThreadStart(client_thread(cl_socket)));
54
                cl_thread.Start();
55
            }
56
           
57
        } 
58
    }
Funkioniert so leider auch nicht, das übergeben des cl_socket nimmt er 
so nicht hin. Ich habe schon recht viel aussen rum gebaut und würde das 
jetzt ungern alles wegschmeissen, wär super wenn mir da jemand einen 
konkreten Tip geben könnte.

von Arc N. (arc)


Lesenswert?

Es gibt ThreadStart und ParameterizedThreadStart

http://msdn.microsoft.com/de-de/library/system.threading.threadstart(v=vs.80).aspx
http://msdn.microsoft.com/de-de/library/system.threading.parameterizedthreadstart(v=vs.80).aspx

oder die Fehlermeldungen beachten und die richtigen Typen verwenden bzw. 
den Thread und die Parameter kapseln.
http://msdn.microsoft.com/de-de/library/ts553s52(v=vs.80).aspx

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Martin schrieb:
> wär super wenn mir da jemand einen
> konkreten Tip geben könnte.

Teil Das Problem auf: Eine Klasse welche einen Socket im Konstruktor 
übernimmt, einen Thread startet und von dem Socket liest/schreibt.
In der Serverklasse erzeugst du bei jedem Accept einfach eine neue 
Instanz der neuen Klasse.

Das ist nicht nur universeller sondern auch weniger Fehleranfällig.

von Martin (Gast)


Lesenswert?

Läubi ich habe versucht deinen Vorschlag umzusetzen:
1
namespace TCPServer
2
{
3
    public class My_server
4
    {
5
        public My_server(Socket mysocket)
6
        {
7
            this.mysocket = mysocket;
8
            mythread = new Thread(new ThreadStart(client_thread));
9
            mythread.Start();
10
        }
11
12
        public Socket mysocket;
13
        public Thread mythread;
14
15
        public void client_thread()
16
        {
17
            Console.WriteLine("Test " + mysocket.RemoteEndPoint);
18
            string tmp = null;
19
            while (mysocket.Connected == true)
20
            {
21
                byte[] b = new byte[200];
22
                char[] c = new char[200];
23
                int k = mysocket.Receive(b);
24
                for (int i = 0; i < k; i++)
25
                {
26
                    Console.Write(Convert.ToChar(b[i]));
27
                    c[i] = Convert.ToChar(b[i]);
28
                }
29
                tmp = new string(c);
30
                //convert_vs(tmp);
31
                tmp = null;
32
                ASCIIEncoding enc = new ASCIIEncoding();
33
            }
34
            Console.WriteLine("Verbindung beendet");
35
        }
36
    }
37
    
38
    public partial class Form1 : Form
39
    {
40
        public Thread mythread = null;
41
        public TcpListener listener = null;
42
        public Thread cl_thread;
43
        Socket s;
44
45
        public Form1()
46
        {
47
            InitializeComponent();
48
            mythread = new Thread(new ThreadStart(listen_tcp));
49
            mythread.Start();
50
        }
51
52
        private void Form1_Load(object sender, EventArgs e)
53
        {
54
55
        }
56
57
        private void listen_tcp()
58
        {      
59
            IPAddress ipAddress = IPAddress.Any;
60
            listener = new TcpListener(ipAddress, 12345);
61
            listener.Start();
62
            Console.WriteLine("Server is running");
63
            Console.WriteLine("Listening on port " + 12345);
64
            Console.WriteLine("Waiting for connections...");
65
            while (true)
66
            {
67
               s = listener.AcceptSocket();
68
               My_server my = new My_server(s);
69
            }
70
           
71
        } 
72
    }
73
}
Leider bleibt das Problem bestehen. Ist vllt in der Empfangsroutine an 
sich ein Fehler, eine Variable die überläuft etc?

von Martin (Gast)


Lesenswert?

Hier noch eine Variante bei der jedesmal eine neue Instanz der My_server 
Klasse erstellt wird. Kommen keine Werte mehr an und ich connecte 
erneut, erhalte ich allerdings gleich von Anfang an keine Werte.
1
namespace TCPServer
2
{
3
    public class My_server
4
    {
5
        public My_server(Socket mysocket)
6
        {
7
            this.mysocket = mysocket;
8
            mythread = new Thread(new ThreadStart(client_thread));
9
            mythread.Start();
10
        }
11
12
        public Socket mysocket;
13
        public Thread mythread;
14
15
        public void client_thread()
16
        {
17
            Console.WriteLine("Test " + mysocket.RemoteEndPoint);
18
            string tmp = null;
19
      
20
            while (mysocket.Connected == true)
21
            {
22
                byte[] b = new byte[200];
23
                char[] c = new char[200];
24
                int k = mysocket.Receive(b);
25
                for (int i = 0; i < k; i++)
26
                {
27
                    Console.Write(Convert.ToChar(b[i]));
28
                    c[i] = Convert.ToChar(b[i]);
29
                }
30
                tmp = new string(c);
31
                //convert_vs(tmp);
32
                tmp = null;
33
                ASCIIEncoding enc = new ASCIIEncoding();
34
            }
35
            Console.WriteLine("Verbindung beendet");
36
        }
37
    }
38
    
39
    public partial class Form1 : Form
40
    {
41
        public Thread mythread = null;
42
        public TcpListener listener = null;
43
        public Thread cl_thread;
44
        Socket s;
45
        int count = 0;
46
47
        public Form1()
48
        {
49
            InitializeComponent();
50
            mythread = new Thread(new ThreadStart(listen_tcp));
51
            mythread.Start();
52
        }
53
54
        private void Form1_Load(object sender, EventArgs e)
55
        {
56
57
        }
58
59
        private void listen_tcp()
60
        {      
61
            IPAddress ipAddress = IPAddress.Any;
62
            listener = new TcpListener(ipAddress, 12345);
63
            listener.Start();
64
            My_server[] my = new My_server[10];
65
            Console.WriteLine("Server is running");
66
            Console.WriteLine("Listening on port " + 12345);
67
            Console.WriteLine("Waiting for connections...");
68
            while (true)
69
            {
70
               s = listener.AcceptSocket();
71
               my[count] = new My_server(s);
72
               count++;
73
            }
74
           
75
        } 
76
    }
77
}

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Martin schrieb:
> tmp = null;
> ASCIIEncoding enc = new ASCIIEncoding();
Was soll das bewirken?

Martin schrieb:
> my[count] = new My_server(s);
> count++;
AUA was soll sowas? Bitte nicht solche Konstrukte in einer Schleife 
ohne Boundcheck und was soll das überhaupt?
 1) C# kennt Listen welche sich um das Speichermanagment kümmern
 2) du verwendest die Referenz nie also wozu aufheben?

Martin schrieb:
> Kommen keine Werte mehr an und ich connecte
> erneut, erhalte ich allerdings gleich von Anfang an keine Werte

Zeig doch mal deinen Clientcode.... der Server sieht (bis auf die 
Anmerkungen) ganz okay aus.

von Martin (Gast)


Lesenswert?

Hallo Läubi, hier der Client:
1
int main()
2
{
3
  WSADATA wsa;
4
  SOCKET mysocket;
5
  SOCKADDR_IN addr;
6
  long rc;
7
  char mystring[100] = "";
8
  int i = 0;
9
10
  if(WSAStartup(MAKEWORD(2,0),&wsa)!=0) 
11
    printf("Winsock konnte nicht gestartet werden\n");
12
  else
13
    printf("Winsock gestartet\n");
14
15
  mysocket=socket(AF_INET,SOCK_STREAM,0);
16
17
  if(mysocket==INVALID_SOCKET)
18
  {
19
    printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError());
20
    return 1;
21
  }
22
  else
23
  {
24
    printf("Socket erstellt!\n");
25
  }
26
  memset(&addr,0,sizeof(SOCKADDR_IN));
27
  addr.sin_family=AF_INET;
28
  addr.sin_port=htons(12345); // wir verwenden mal port 12345
29
  addr.sin_addr.s_addr=inet_addr("127.0.0.1"); // zielrechner ist unser eigener
30
  rc=connect(mysocket,(SOCKADDR*)&addr,sizeof(SOCKADDR));
31
  if(rc==SOCKET_ERROR)
32
  {
33
    printf("Fehler: connect gescheitert, fehler code: %d\n",WSAGetLastError());
34
    return 1;
35
  }
36
  else
37
  {
38
    printf("Verbunden mit 127.0.0.1..\n");
39
  }
40
  send(mysocket,mystring,sizeof(mystring),0);
41
  strcpy(mystring,"Verbunden\n");
42
  send(mysocket,mystring,9,0);
43
  
44
  while(1)
45
  {
46
    i++;
47
    sprintf(mystring, "%d\n",i);
48
    send(mysocket,mystring,sizeof(mystring),0);
49
    printf("%d",i);
50
    Sleep(500);
51
  }
52
  return 0;
53
}
Was meinst du genau mit Boundcheck?
> ASCIIEncoding enc = new ASCIIEncoding(); hat keine Funktion hier, hab ich 
vergessen rauszuschmeissen. Grüße Martin

von Finchi (Gast)


Lesenswert?

Schreib den Server nochmal ordentlich neu, benenne Variablen richtig, 
benutze Klassen und kommentiere deinen Code. Beachte dabei folgende 
Seiten:

http://msdn.microsoft.com/de-de/library/system.net.sockets.tcplistener.aspx

http://msdn.microsoft.com/de-de/library/system.net.sockets.tcpclient.aspx

http://www.vb-paradise.de/allgemeines/tipps-tricks-und-tutorials/internet-lan/16242-ausfuehrliches-tcp-und-udp-tutorial/#post94565 
(Ist zwar VB.NET aber trotzdem gut erklärt)

MFG

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.