Permalänk
Medlem

C(++) Sockets och Threads

Håller på att göra en multitrådad webserver, för varje socket accept jag gör ska jag skapa en tråd som jag skickar in i en tråd, funkar skit fint utan trådar men när jag väl skickar med socketen till en ny tråd verkar det som att den förlorar alla sin värden eller något sådant, får lite skumma errors. Jag gör förmodligen något fel, postar relevanta delar av koden.

Hur det ser ut i main:

struct sockaddr clientAddr; int clientAddrLen = sizeof(clientAddr); SOCKET s1 = accept(s,&clientAddr,&clientAddrLen); if(s1 != INVALID_SOCKET) { _beginthread(Server,0,(void*)&s1); }

och sedan hur det ser ut på "Server" trådens början då jag typar om den och tar emot meddelandet, som bara blir en tom sträng...

void Server( void *s) { SOCKET s1 = *(SOCKET*)s; char hostName[100]; char portName[100]; time_t lt; lt = time(NULL); // Vänta på inkommande anrop struct sockaddr clientAddr; int clientAddrLen = sizeof(clientAddr); if(s1 != INVALID_SOCKET) { int ok = getnameinfo(&clientAddr,clientAddrLen,hostName,100,portName,100,NI_NUMERICSERV ); if(ok == 0) { printf("Accept incoming from: %s at port %s\n",hostName,portName); } } // Skriv ut meddelandet från klienten, remade int iResult; char inputHTTP[512] = {0}; iResult = recv(s1, inputHTTP, 512, 0);

Har sökt runt på detta ganska länge nu och alla exempel ser exakt likadant ut för mig men... blir bara kalle kalas av det hela :s även variablerna "hostName" och "portName" blir bara skräpvärden...

har också prövat med CreateThread() men samma sak där, all hjälp uppskattas tackar!

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk
Medlem

Åhh! Det här låter intressant

Kan du skicka hela klabbet tro så att man får vara med och felsöka?

(Rent spontant skulle jag gissa på att något knas med pekarna, något faller ur scope eller glömt volatile)

Visa signatur

citera!

Permalänk
Medlem

SOCKET s1 ligger på stacken, och går out of scope när funktionen returnerar.
http://en.wikibooks.org/wiki/C%2B%2B_Programming/Scope

Det du bör göra är följande:
_beginthread(Server,0,(void*)s1);

och i Server() casta om argumentet till en SOCKET och inte en SOCKET *.

Visa signatur

Intel Core i7-3770K | NVIDIA Geforce GTX 980 | 16 GB DDR3 | DELL P2415Q | DELL U2711 | DELL U2410

Permalänk
Medlem

Borde man inte använda dynamisk minnesallokering här istället för att kasta till (void*)?
Man kan ju lätt mista sig för att det är en pekare och inte data.

Visa signatur

citera!

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Dosshell
Borde man inte använda dynamisk minnesallokering här istället för att kasta till (void*)?
Man kan ju lätt mista sig för att det är en pekare och inte data.

Nej, man kan utan problem casta om en SOCKET till en void * sålänge sizeof(SOCKET) <= sizeof(void *), vilket uppfylls både i 32/64 bitars läge.

Visa signatur

Intel Core i7-3770K | NVIDIA Geforce GTX 980 | 16 GB DDR3 | DELL P2415Q | DELL U2711 | DELL U2410

Permalänk
Medlem

Prövade nu
_beginthread(Server,0,(void*)s1);

och

SOCKET s1 = (SOCKET)s;

Castar om fint osv, men socketen som kommer fram har samma värde men när jag kör recv för att få meddelandet och så vidare.
Kan gärna skicka allt, det är för en skolgrej suttit med detta i tre dagar snart, så har verkligen givit det mitt allt.

dannne1@hotmail.com @msn

getnameinfo(&clientAddr,clientAddrLen,hostName,100,portName,100,NI_NUMERICSERV );

får jag bara massa skräp

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk
Medlem

Tack förresten för tipsen, försöker vidare

Säg till här om ni har fler tips eller ideer

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk

Härligt att en ny tråd om ett snarlikt problem finns här. Mer info!
http://www.sweclockers.com/forum/showthread.php?s=&threadid=9...

Nu vet jag inte om det är smart, men det jag har gjort är att skapat egna klasser för Windows sockets, vilket inte bara gör koden mer lättnavigerad men hindrar även att man inte problem med att variablar och dyl. hamnar utanför "scopet" av funktionerna man skall köra. Bara att hojta om du vill ha dem.

Visa signatur

Asus Maximus II formula, E8400 @ 3.9GHz, 4GB Dominator DDR2, Radeon HD4850.

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av SwedishPshyco
Härligt att en ny tråd om ett snarlikt problem finns här. Mer info!
http://www.sweclockers.com/forum/showthread.php?s=&threadid=9...

Nu vet jag inte om det är smart, men det jag har gjort är att skapat egna klasser för Windows sockets, vilket inte bara gör koden mer lättnavigerad men hindrar även att man inte problem med att variablar och dyl. hamnar utanför "scopet" av funktionerna man skall köra. Bara att hojta om du vill ha dem.

Inte så mycket info där, de länkarna som fanns i andra tråden har jag redan kollat på och sedan ska detta arbetet vara ganska enkelt så ska inte behöva skapa egna klasser för det. Sedan ska det vara gjort i C så mycket som möjligt, inte jobbat i C på länge men inte objektorienterat?

Tack, följer dock hans tråd och ser ifall det finns något jag kan snappa upp!

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk
Medlem

Re: C(++) Sockets och Threads

Citat:

Ursprungligen inskrivet av erdraug

struct sockaddr clientAddr; int clientAddrLen = sizeof(clientAddr); if(s1 != INVALID_SOCKET) { int ok = getnameinfo(&clientAddr,clientAddrLen,hostName,100,portName,100,NI_NUMERICSERV ); if(ok == 0) { printf("Accept incoming from: %s at port %s\n",hostName,portName); } }

getnameinfo tar en redan "ifylld" struct sockaddr och extraherar data från den. Du ger istället en icke ifylld struktur. Du har två alternativ som jag kommer på:

1) Använd getpeerinfo för att fylla i din struct sockaddr innan anropet till getnameinfo.

2) Skapa en egen struct som representerar en ansluten klient. Denna håller den SOCKET och struct sockaddr som accept gav dig, tillsammans med annan relevant data. Skicka ett (gärna dynamiskt allokerat) objekt av denna typ till din tråd.

Då ditt projekt låter någorlunda icke-trivialt (webbserver) lutar jag åt att den ökade strukturen andra alternativet kan ge. Detta gör även att informationen inte behöver hämtas ut två gånger.

Angående andra problemet; hur ser du att du får en tom sträng? Är iResult == 0? I så fall fanns helt enkelt ingen data innan sändaren stängde sin socket. Är iResult == -1 kan du använda perror eller strerror för att få en beskrivning av vad som gått fel, eller alternativt kolla errno själv. Är iResult > 0 har du fått en icke-tom sträng, och din utskrift är fel (om det är via utskrift du ser att den är tom). Det skulle i så fall även kunna vara att den mottagna strängen börjar med en 0-byte.

Visa signatur

Vill du ha svar? Citera mig gärna.

Permalänk
Medlem

Alltså projektet skall inte vara så stort, har inte en aning om hur jag gör en struct, meningen är att man ska vara 5 personer på detta och detta är egentligen en liten del av laborationen, bara det att alla mina gruppmedlemmar har hoppat av så jag är ensam kvar :/ mindre roligt.

Men nu förstår jag vad som är felet, jag måste på något sätt som du säger skicka med värdena som skapas i accept.

Märkte nu att Recv har fixats efter att jag följde tidigare råd! en liten bit på vägen men nu kan jag sova lugnare!

Tackar på förhand, detta hjälpte mig verkligen, men nu stupar jag snart, suttit med detta sedan 4 i eftermiddags. Natti natt!

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av lajnold

1) Använd getpeerinfo för att fylla i din struct sockaddr innan anropet till getnameinfo.

Har du något bra exempel på detta? Vore snällt med relativt snabbt svar, uppgiften skall vara klar till ikväll och tänkte åtminstone ha trådarna klara tills dess, sedan får det bli komplettering på resten så länge

getpeerinfo borde räcka vad jag kan se, ger mig hostname och port som jag är ute efter, får den dock inte att fungera...

Tack igen!

EDIT: Prövade nu att skapa en struct efter att läst lite guider, får nu error på raderna:

_beginthread(Server,0,(void*)conn);

och

Connections conn = (Connections)s;

Den första raden i min main då där jag skickar min struct "conn" och andra i tråden när jag typecastar om void* till min struct som heter Connections.

Felet jag får är "Cannot convert from connections to void* och vice versa för andra raden... :s

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av erdraug
Har du något bra exempel på detta? Vore snällt med relativt snabbt svar, uppgiften skall vara klar till ikväll och tänkte åtminstone ha trådarna klara tills dess, sedan får det bli komplettering på resten så länge

getpeerinfo borde räcka vad jag kan se, ger mig hostname och port som jag är ute efter, får den dock inte att fungera...

Jag skrev visst fel. getpeername ska det vara. Den används liknande:

struct sockaddr_in clientAddr; socklen_t clientAddrLen = sizeof(clientAddr); if (getpeername(s1, &clientAddr, &clientAddrLen) == -1) { perror("getpeername"); /* Perhaps return? */ } if (getnameinfo(&clientAddr, clientAddrLen, other arguments ...) == -1) { perror("getnameinfo"); /* Return? */ }

Notera att jag ersatt struct sockaddr med struct sockaddr_in, vilket kan hålla all relevant information om en IPv4-adress, vilket inkluderar portnummer.

Visa signatur

Vill du ha svar? Citera mig gärna.

Permalänk
Medlem

Prövade nu att skapa en struct efter att läst lite guider, får nu error på raderna:

_beginthread(Server,0,(void*)conn);

och

Connections conn = (Connections)s;

Den första raden i min main då där jag skickar min struct "conn" och andra i tråden när jag typecastar om void* till min struct som heter Connections.

Felet jag får är "Cannot convert from connections to void* och vice versa för andra raden... :s

Prövar nu getpeername som du föreslod

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av lajnold
Jag skrev visst fel. getpeername ska det vara. Den används liknande:

struct sockaddr_in clientAddr; socklen_t clientAddrLen = sizeof(clientAddr); if (getpeername(s1, &clientAddr, &clientAddrLen) == -1) { perror("getpeername"); /* Perhaps return? */ } if (getnameinfo(&clientAddr, clientAddrLen, other arguments ...) == -1) { perror("getnameinfo"); /* Return? */ }

Notera att jag ersatt struct sockaddr med struct sockaddr_in, vilket kan hålla all relevant information om en IPv4-adress, vilket inkluderar portnummer.

struct sockaddr_in clientAddr; socklen_t clientAddrLen = sizeof(clientAddr); getpeername(s1, &clientAddr, &clientAddrLen); getnameinfo(&clientAddr, clientAddrLen,hostName,100,portName,100,NI_NUMERICSERV);

Kör jag nu då, men får typecast fel då...

'getpeername' : cannot convert parameter 2 from 'sockaddr_in *' to 'sockaddr *'

och

'getnameinfo' : cannot convert parameter 1 from 'sockaddr_in *' to 'const SOCKADDR *'

Så den gillar inte riktigt sockaddr_in som du använt där, jag vet heller inte riktigt vad det är.. inte hemma på detta direkt

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk
Medlem

_beginthread(Server,0,(void*)conn);

och

Connections conn = (Connections)s;

Löste jag halvt genom att skriva

_beginthread(Server,0,(void*)&conn);

fast

Connections conn = (Connections)s;

får jag fortf fel på, hur typecastar jag en struct ordentlige med pekare osv?

Denna lösningen verkar lättare tycker jag, om det är som jag tror

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk
Medlem

Jag jobbade med sockets i ett projekt på jobbet förra året. Där så skapade jag en klass för klienterna som hade sina egna trådar som den behövde.
Jag skickade med socket in i constructorn och hade aldrig några problem med att behöva casta eller att den tappade informationen.

Jag hade en lyssnartråd som lyssnade på anslutningar och skapade klient-objekt för varje anslutning.
Nått i stil med:
SOCKET ClientSocket = accept( parameters... ); // fånga en anslutning
CClient *pClient = new CClient( ClientSocket ); // skapa ett klient-objekt
pClient->bCreate(); // skapa resurser och trådar i klient-objektet

I classen CClient kunde jag sedan jobba med ClientSocket som jag ville.

Visa signatur

Legitimerad stofil

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Rusiak
Jag jobbade med sockets i ett projekt på jobbet förra året. Där så skapade jag en klass för klienterna som hade sina egna trådar som den behövde.
Jag skickade med socket in i constructorn och hade aldrig några problem med att behöva casta eller att den tappade informationen.

Jag hade en lyssnartråd som lyssnade på anslutningar och skapade klient-objekt för varje anslutning.
Nått i stil med:
SOCKET ClientSocket = accept( parameters... ); // fånga en anslutning
CClient *pClient = new CClient( ClientSocket ); // skapa ett klient-objekt
pClient->bCreate(); // skapa resurser och trådar i klient-objektet

I classen CClient kunde jag sedan jobba med ClientSocket som jag ville.

Får inte skapa klasser för denna labben enligt speccen ifrån läraren :/

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av erdraug
getpeername' : cannot convert parameter 2 from 'sockaddr_in *' to 'sockaddr *'

och

'getnameinfo' : cannot convert parameter 1 from 'sockaddr_in *' to 'const SOCKADDR *'

Så den gillar inte riktigt sockaddr_in som du använt där, jag vet heller inte riktigt vad det är.. inte hemma på detta direkt

clientAddrs adress måste castas till struct sockaddr*. Jag tycker även att du borde ha kvar felkontrollerna som jag skrev dit. Kontrollera även vad resterande socket-funktioner returnerar.

Citat:

Ursprungligen inskrivet av erdraug
_beginthread(Server,0,(void*)conn);

och

Connections conn = (Connections)s;

Löste jag halvt genom att skriva

_beginthread(Server,0,(void*)&conn);

fast

Connections conn = (Connections)s;

får jag fortf fel på, hur typecastar jag en struct ordentlige med pekare osv?

Det du får in är en adress (void-pekare). En adress kan inte castas till en struct. Däremot kan den castas till pekare-till-struct, vilket är vad du vill göra. I din tråd-funktion borde conn alltså vara av typen Connection*. Tänk på att allokera objektet dynamiskt (malloc) innan du ger det till tråden, och att sedan frigöra det när/innan tråden avslutas. Allokerar du det inte dynamiskt riskerar det att falla sönder innan din tråd är klar med det.

Visa signatur

Vill du ha svar? Citera mig gärna.

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av lajnold
[B] clientAddrs adress måste castas till struct sockaddr*. Jag tycker även att du borde ha kvar felkontrollerna som jag skrev dit. Kontrollera även vad resterande socket-funktioner returnerar.

okok, testar detta:

Så här börjar tråden:

SOCKET s1 = (SOCKET)s; char hostName[100]; char portName[100]; struct sockaddr_in clientAddr; socklen_t clientAddrLen = sizeof(clientAddr); int a = getpeername(s1, (struct sockaddr*)&clientAddr, &clientAddrLen); int k = getnameinfo((struct sockaddr*)&clientAddr, clientAddrLen,hostName,100,portName,100,NI_NUMERICSERV); int iResult; char inputHTTP[512] = {0}; iResult = recv(s1, inputHTTP, 512, 0);

Får fortfarande bara massa skräpvärden i mina portName och hostName variabler, märker idag också att recv inte fungerar, alltså socketen som jag skickar verkar vara helt värdelös, int a blir 0 och int k blir 10093

Så här ser det ut i main där jag startar tråden:

SOCKET s1 = accept(s,&clientAddr,&clientAddrLen); if(s1 != INVALID_SOCKET) { _beginthread(Server,0,(void*)s1); }

Förslag?

PS: Kör jag med felhanteringen du föreslod får jag bara outputen: "getpeername: no error" :s

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)

Permalänk
Medlem

GAAAAHHHH okey, tackar för hjälpen alla min trådning funkar nu och recv funkar också, fick dock massa fel, mest dock för att jag körde:

closesocket(s);
WSACleanup();

i main... dock hade var det dock inte det som förstörde mina
getpeername
och
getnameinfo

men nu funkar hela trådningen, skall fixa ett telnet admin gränssnitt också med vissa kommandon, fast det får bli komplettering på det.

Tackar igen för hjälpen! varit skit bra!

Visa signatur

| CPU: Intel Core i5 3570K | Mobo: MSI Z77A-GD65 ATX | Ram: Corsair 16GB (4x4096MB) CL9 1600Mhz VENGEANCE | GFX: Gigabyte HD7970 OC 3GB | SSD: Corsair Force 3 120GB | HDD: Diverse Mekaniska 4TB | Chassi: Corsair 800D | PSU: Corsair AX 850W 80+ Gold Modulär | CPU Cooler: Corsair H50 |
Citera mig så hittar jag tillbaka hit :)