Permalänk
Medlem

C# Sockets

Hej,

Sitter och försöker lära mig sockets i C#, och skrev ihop ett litet filöverföringsprogram som verkade fungera bra, ända tills jag testade att ansluta till en annan IP-address än 127.0.0.1.

Kunde inte förstå varför det inte fungerade, så jag skrev en så liten server/klient som möjligt för att försäkra mig om att det inte var jag som gjorde något helt fel. Kan upplysa innan om att jag inte har tagit några kurser i detta, jag har bara läst någon tutorial på internet, så det är mycket möjligt att jag gör något helt knasigt. Här är min klient/server:

Citat:

Klient:

byte[] data = Encoding.ASCII.GetBytes("HI!");

Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEnd = new IPEndPoint(IPAddress.Parse("218.211.64.59"), 7779);
clientSocket.Connect(ipEnd);

for (int i = 0; i < 3; i++)
{
clientSocket.Send(data);
System.Console.WriteLine("Data sent");
}

Citat:

Server:

byte[] data = new byte[10];

Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEnd = new IPEndPoint(IPAddress.Any, 7779);
serverSocket.Bind(ipEnd);
serverSocket.Listen(10);

Socket clientSocket = serverSocket.Accept();

for (int i = 0; i < 3; i++)
{
clientSocket.Receive(data);
System.Console.WriteLine(Encoding.ASCII.GetString(data));
}

När jag använder min externa IP-Address så får jag "Data sent"x3 i serverkonsollen och "HI!"x1 i klientkonsollen, klienten sitter fast vid clientSock.Receive, den andra upprepningen. Men om jag istället ansluter till 127.0.0.1 får jag "Data sent"x3 och "HI!"x3, som jag väl borde få alltid (?). Sitter i DMZ i routern, och windows brandväggen av, har inte någon annan brandvägg på heller.

Kan också tillägga att det har ingen betydelse om det är klienten eller servern som skickar/tar emot.

Tack på förhand!

Permalänk

utan att kika i koden för mycket undrar man ju om du har öppnat port 7779?

Visa signatur

Asus Striker II Extreme / XFX Geforce GTX 280 / Q9450 @ 3.6GHz/ TRUE Noctua 120/ 4x1GB Corsair TWIN3X2048-1333C9DHX / X25-M G2 80gb Velociraptor / Win 7 Ultimate x64/ Antec P190

MovieDatabase

Permalänk
Medlem

Jodå, porten är öppen. Och om det skulle ha något att göra med det så skulle det väl inte fungera första gången heller, eller?

Permalänk
Citat:

Ursprungligen inskrivet av Goose7
Jodå, porten är öppen. Och om det skulle ha något att göra med det så skulle det väl inte fungera första gången heller, eller?

Jo, ansluter du till dig själv (127.0.0.1) men om du ansluter till dig själv med en extern ip kommer du att gå via routern och då få en annan säkerhetsnivå

Visa signatur

Asus Striker II Extreme / XFX Geforce GTX 280 / Q9450 @ 3.6GHz/ TRUE Noctua 120/ 4x1GB Corsair TWIN3X2048-1333C9DHX / X25-M G2 80gb Velociraptor / Win 7 Ultimate x64/ Antec P190

MovieDatabase

Permalänk
Medlem

Men, första gången funkar det även om jag använder min externa IP. Jag skickar "HI!" 3 gånger, när jag använder min externa IP kommer det första meddelandet fram, vilket jag inte tror det hade gjort om det hade varit min router. Jag har fått programmet att kunna skicka tre gånger, men bara om jag disconnectar och connectar mellan varje send, vilket inte är optimalt om man ska ha ett filöverföringsprogram som ska skicka filer i små delar i taget.

Permalänk
Hedersmedlem
Citat:

Ursprungligen inskrivet av Goose7
Jag har fått programmet att kunna skicka tre gånger, men bara om jag disconnectar och connectar mellan varje send, vilket inte är optimalt om man ska ha ett filöverföringsprogram som ska skicka filer i små delar i taget.

Detta

for (int i = 0; i < 3; i++) { clientSocket.Receive(data); System.Console.WriteLine(Encoding.ASCII.GetString(data)); }

borde läsa in "HI!HI!HI!" till data, skriva ut det och sedan vänta (blockerande) på mer data. Jag antar att du egentligen vill att programmet skall tolka det du skickar som tre olika paket, men det får du i så fall implementera själv.

Permalänk
Medlem

Men det jag inte förstår är varför den läser in "HI!" första gången, och andra gången fastnar den på Receive. Skulle varit lättare att förstå om det som du säger läste in "HI!HI!HI!". Om det inte finns någon data att ta emot, ska den inte returnera 0 och fortsätta?

Permalänk
Hedersmedlem
Citat:

Ursprungligen inskrivet av Goose7
Skulle varit lättare att förstå om det som du säger läste in "HI!HI!HI!". Om det inte finns någon data att ta emot, ska den inte returnera 0 och fortsätta?

Man kan heller aldrig vara säker på hur mycket data som faktiskt finns när man läser; kanske finns "HI!", kanske "HI!HI!HI!", eller också bara "H". Anropet ovan läser in maximalt 10 byte om det finns något att läsa och väntar i annat fall. För att se hur mycket data som finns kan man använda
clientSocket.Available

Permalänk
Medlem

Okej, jag är fortfarande inte säker på att jag förstår vad man ska göra åt det, testade något annat nu. Istället för att klienten skickar 3 gånger så ska klienten skicka "HI!" och sen vänta på ett svar från servern innan den skickar nästa "HI!".

Serverns for-sats ser ut så här:

Citat:

clientSocket.Receive(data, 0, 3, SocketFlags.None);
System.Console.WriteLine(Encoding.ASCII.GetString(data));
clientSocket.Send(new byte[] { 1 });
System.Console.WriteLine("Response sent");

Klientens for-sats ser ut så här:

Citat:

clientSocket.Send(data);
System.Console.WriteLine("Data sent");
clientSocket.Receive(new byte[] { 0 }, 1, SocketFlags.None);
System.Console.WriteLine("Response received");

Klienten/servern vet nu hur många bytes dom ska ta emot. Men vad som händer är:

Klienten skickar "HI!"
Servern tar emot "HI!"
Servern skickar ett svar (en byte)
Klienten tar emot svaret (en byte)
Klienten skickar "HI!"
Servern tar aldrig emot "HI!"
Klienten väntar på svar från servern som aldrig kommer eftersom att "HI!" inte kom fram.

Enligt serverns clientSocket.Available så finns ingen data tillgänlig. Som du sa så väntar clientSocket.Receive om det inte finns någon data, det är vad den gör, men varför finns ingen data här, när jag precis tidigare har skickat en "begäran" från servern att den är redo att ta emot nästa meddelande? I detta fallet så kan jag omöjligt ha läst alla "HI!" (eller delar av alla) samtidigt eftersom att klienten väntar på serverns svar innan den skickar nästa. Finns det någon flush eller något liknande man måste köra mellan varje Send?

Allt funkar när jag använder en intern IP eller 127.0.0.1, men ej när jag använder en extern IP. Det verkar som sagt som om jag bara kan skriva till en socket en gång, är det meningen?

EDIT: Kan tillägga att precis samma sak inträffar om jag använder en NetworkStream

Permalänk
Hedersmedlem

Testa att istället använda

System.Console.WriteLine(Encoding.ASCII.GetString(data, 0,3));

För övrigt skall det inte behövas några svar (tcp hanterar eventuella förlorade paket soch sådant på egen hand. Och en annan enkel lösning är att först skicka en paketstorlek av känd storlek (till exempel en uint16) och sedan så många byte. Mottagaren kan då vänta tills det finns två byte (för en uint16) tillgängliga, läsa in paketstorleken, vänta tills så många byte finns tillgängliga och slutligen läsa in dessa.

Och när man ändå håller på är det förmodligen smidigare att använda klasser som tcplistener, tcpclient, binaryreader och binarywriter.

Permalänk
Medlem

Problemet är inte att skriva ut data, problemet är att programmet fastnar på socket.Receive.

Om jag skulle ändra writeline raden till

"System.Console.WriteLine("Gås");"

så skulle det skriva gås efter att ha fått första meddelandet, men sen skulle det fastna på

"clientSocket.Receive(data, 0, 3, SocketFlags.None);"

andra gången den försöker ta emot data, och stå där till jag får SocketException was unhandled, "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond"

Grejen är att om jag kör socket.Disconnect och sen skapar en ny socket och kör socket.Connect(ipEnd) (och självklart accepterar ny anslutning med server också) varje gång innan jag skickar så fungerar det fint. Det fungerar alltså bara att köra socket.Send(...) en gång per socket.

Permalänk
Hedersmedlem
Citat:

Ursprungligen inskrivet av Goose7
Om jag skulle ändra writeline raden till

"System.Console.WriteLine("Gås");"

Har du testat detta, eller är det bara hur det verkar vara? Jag testade och fick det första fallet:

HI!

respektive

Data sent Response received Data sent Response received Data sent Response received

och i det andra:

Gås Response sent Gås Response sent Gås Response sent

respektive

Data sent Response received Data sent Response received Data sent Response received

Permalänk
Medlem

Jag har testat det, och jag får inte samma resultat som du får. Alltså så är det antagligen något med min router ändå - trots att jag har testat att porten är öppen och jag har DMZ på. Bra att veta att det inte är jag som tänker helt knasigt i alla fall. Får testa utan routern när jag har tid. Tack för hjälpen!

Jag får:

Citat:

Gås
Response sent

Respektive

Citat:

Data sent
Response received
Data sent

Sen SocketException