[gelöst]Sporadische Socket-Kommunikation zwischen VM und Host



  • Hallo Leute,

    ich habe das Problem, dass sich der Client mal erfolgreich mit dem Server connecten kann und mal nicht.

    Zunächst beischreibe ich kurz das Setting: der Client-Socket läuft auf dem Windows 7 Hostsystem in C#, während der Server in der Ubuntu VM läuft und in C programmiert wurde.
    Weiter unten wird mein Problem und Ziel dieser Aktion noch näher erläutert.

    Client Konfiguaration Host:
    Windows 7
    WLAN
    IP:192.168.1.2
    Subent:255.255.255.0
    Gateway:192.168.1.1
    Firewall AUS

    Socket socket = null;
    
                    System.Net.IPEndPoint ep = new System.Net.IPEndPoint(IPAddress.Parse("192.168.1.3"),5000);
                    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
                    socket.Connect(ep);
    
                    socket.Send(System.Text.Encoding.ASCII.GetBytes("A"));
                    socket.Close();
    

    Server Konfiguaration Guest:
    Ubuntu 12.10
    Bridged und WLAN Adapter in der Auswahl
    IP: 192.168.1.3
    Subnet: 255.255.255.0
    Gateway: 192.168.1.1
    Firewall per default aus

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <time.h> 
    
    int main(int argc, char *argv[])
    {
        int listenfd = 0, connfd = 0;
        struct sockaddr_in serv_addr; 
    
        char recvBuff[1];
        listenfd = socket(AF_INET, SOCK_STREAM, 0);
        memset(&serv_addr, '0', sizeof(serv_addr));
        memset(recvBuff, '0', sizeof(recvBuff)); 
    
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        serv_addr.sin_port = htons(5000); 
        bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 
    
        listen(listenfd, 10); 
    
        while(1)
        {
            connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 
            read(connfd, recvBuff, sizeof(recvBuff));
    	if(recvBuff[0]=='A')
    	{
    		close(connfd);
    		return 0;
    	}
    
            close(connfd);
            sleep(1);
         }
    }
    

    Funktionsweise des Beispielprogramms: Der Client sendet ein character Zeichen, worauf hin der Server einfach beendet wird. Es ist wie gesagt exemplarisch. In der kaum erweiterten Endfassung wird später beim Erhalt eines bestimmten ein bestimmter Befehl ausgeführt. Genauer gesagt Befehle an eine Flugdrohne von Parrot. Das spielt hier aber keine Rolle.
    Manchmal kann ich mit diesem Code den Server 5,6,7 Mal hintereinander ohne Probleme ausschalten. Dann klappt es wieder ohne eine Veränderung gar nicht und ich bekomme eine Zeitüberschreitungsfehlermeldung vom Client, die vom .connect() geworfen wird.

    Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat 192.168.1.3:5000
    

    Merkwürdigerweise sieht der Ping auf den Server so aus:

    C:\User>ping 192.168.1.3
    
    Ping wird ausgeführt für 192.168.1.3 mit 32 Bytes Daten:
    Antwort von 192.168.1.100: Zielhost nicht erreichbar.
    Antwort von 192.168.1.3: Bytes=32 Zeit<1ms TTL=64
    Antwort von 192.168.1.3: Bytes=32 Zeit<1ms TTL=64
    Antwort von 192.168.1.3: Bytes=32 Zeit<1ms TTL=64
    
    Ping-Statistik für 192.168.1.3:
        Pakete: Gesendet = 4, Empfangen = 4, Verloren = 0
        (0% Verlust),
    Ca. Zeitangaben in Millisek.:
        Minimum = 0ms, Maximum = 0ms, Mittelwert = 0ms
    

    Hat jemand eine Idee wieso die Verbindung mal klappt und mal nicht? Wieso erscheint beim Pingen erst die 192.168.1.100? Sind Fehler im Code? Bin für jeden Hinweis dankbar, denn mir gehen mittlerweile die Ideen aus.



  • struct sockaddr_in serv_addr;
    
        char recvBuff[1];
        listenfd = socket(AF_INET, SOCK_STREAM, 0);
        memset(&serv_addr, '0', sizeof(serv_addr));
        memset(recvBuff, '0', sizeof(recvBuff));
    

    Leider machen 90% der Tutorials das hier unnötig mit memset, und du nutzt memset auch noch falsch.
    Du füllt die Speicherbereiche mit '0' statt mit 0, außerdem wertest du den Rückgabewert von recv nicht aus.

    struct sockaddr_in serv_addr={0};
    
        char recvBuff[1]=""; /* Initialisierung von recvBuff ist eigentlich nicht notwendig */
        listenfd = socket(AF_INET, SOCK_STREAM, 0);
    


  • Hallo Wutz,

    erwischt mit dem "Vorwurf" des Tutorials 😉 Habe die Änderungen im Code entsprechend eingebaut. Danke für den Hinweis. Dennoch erreiche ich den Server manchmal nicht.

    Deine Anmerkung

    außerdem wertest du den Rückgabewert von recv nicht aus

    verstehe ich nicht ganz. Meinst du damit das was auf recvBuff gespeichert ist? Das steht doch in der if-Abfage.



  • Nein, du hast mich falsch verstanden, ich gab den Hinweis, dass du den Rückgabewert der Funktion read (bzw. das fast-Äquivalent recv) verwenden sollst, um die korrekte Funktionsausführung zu prüfen.
    Dafür sind diese Rückgabewerte nämlich da.
    Außerdem solltest du dich über nonblocking/blocking Modus für deinen Fall informieren, die haben nämlich entscheidenden Einfluß auf die Arbeitsweise von read/recv.
    Und außerdem ist das alles Unix Zeugs und gehört nicht in C.



  • Es hängt ja nicht an dem read, sondern daran, dass der Client sich manchmal nicht connecten kann. Wenn das läuft funktioniert auch alles andere.
    Ein Umschalten auf den nonblocking Mode hat dabei auch nicht geholfen. Kann mir auch nicht vorstellen, dass es an so etwas liegt, da hier ein Client auf den Server kommt und es zu keinen Irritationen kommen kann.



  • Habe mein Problem nun gelöst und es war kein Vodoo-Zauber nötig, da es mir wirklich nur um einen Client ging der ein einziges Character Zeichen an den Server sendet. Hilfreich dafür waren diese beiden Seiten:

    Networking mit C#
    http://msdn.microsoft.com/de-de/library/bb979208.aspx

    TCP/IP Sockets in C: Practical Guide for Programmers
    http://cs.baylor.edu/~donahoo/practical/CSockets/textcode.html

    Habe mich für den Socket-Server in C des TCPEchoServers bedient und für meine Zwecke leicht abgewandelt.

    In C# sah es für den Client wesentlich einfacher aus. Dazu sei gesagt, dass ich in einer idealisierten Umgebung arbeite, sodass die Verbindung auch wirklich 100% sicher aufgebaut werden kann ohne Störungen und Komplikationen. Das sieht dann so aus:

    TcpClient client = new TcpClient("192.168.1.3", 5000);
    NetworkStream clientStream = client.GetStream();
    byte[] outStream = System.Text.Encoding.ASCII.GetBytes(befehl);
    
    clientStream.Write(outStream, 0, outStream.Length);
    clientStream.Flush();
    client.Close();
    

    Euch noch ein schönes WE 😉


Log in to reply