c++ socket - Bad File Descriptor?

Permalänk
Medlem

c++ socket - Bad File Descriptor?

Hej

Jag försöker bygga en socketserver som skall lyssna på en klient och ge svar tillbaka.

Jag kan ansluta till servern men när klienten börjar skicka data så spottar den ut: ERROR on accept: Bad File Descriptor.

Här är koden:

#include <iostream> #include <string> #include <cstring> #include <sstream> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> using namespace std; void error(char *msg) { perror(msg); exit(1); } int main (int argc, char * const argv[]) { int sockfd, newsockfd, portno; socklen_t clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int P_value = 6435; string u_value; string p_value; int i; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'P': P_value = atoi(argv[++i]); break; case 'u': u_value = argv[++i]; break; case 'p': p_value = argv[++i]; break; } } } if (P_value < 2 || u_value.empty() || p_value.empty()) error("ERROR: To few arguments supplied, look at --help"); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); portno = P_value; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) error("ERROR on binding"); listen(sockfd,5); clilen = sizeof(cli_addr); while (1){ newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) error("ERROR on accept"); int pid; pid=fork(); if (pid < 0) error("ERROR on fork"); if (pid == 0){ close(sockfd); bzero(buffer,256); write(newsockfd,"This is version 0.1 of the API >> ",34); read(newsockfd,buffer,255); printf("Client said: %s",buffer); stringstream ss; string buff; ss << buffer; ss >> buff; size_t userfound; userfound=buff.find(u_value); if(userfound!=string::npos){ cout << "Give me your password >>"; } } else{ close(newsockfd); } } }

Någon som kan hjälpa mig att förstå problemet?

MVH niclas

Permalänk

Skulle det kunna vara för att barnprocessen (som hanterar den inkommande anslutningen) slutför if (pid == 0) blocket och loopar tillbaka till newsockfd = accept(sockfd, ...), där sockfd är en socket som du har stängt?

Permalänk
Medlem

på serversidan gör du close(newsockfd) vilket ju stänger kommunikationskanalen och förmodligen förklarar ditt problem.

Permalänk
Medlem

Om jag tar bort close(newsockfd) så kvarstår problemet

Om jag däremot lägger in i servern att den ska vänta på ett till svar från klienten så kommer inte felet.....förrens klienten svarat.

Det verkar som att servern spottar ut felet efter den sista kommunikationen är gjord. Tills dess verkar det fungera.

/Niclas

Permalänk
Medlem

eftersom det ligger i en loop så kommer den att försöka göra accept om och om igen, men det första du gör efter gaffeln är att stänga sockfd. och efter det fungerar accept dåligt.

jag tror inte du egentligen vill att pid-nollan ska halka ut i while-loopen igen, eller?

Permalänk
Medlem

Tack för hjälpen, jag tror att jag har fixat det nu, återkommer med hur jag löst det senare.

Jag har däremot fått ett annat bekymmer med en annan del av koden nu.

Jag har detta:

int intNumberOfDevices = tdGetNumberOfDevices(); char ts_aliases[255]; int tdName2Id[intNumberOfDevices]; for (int i = 0; i < intNumberOfDevices; i++) { if(i>0){ strcat(ts_aliases,"\n"); } int id = tdGetDeviceId( i ); char *name = tdGetName( id ); char *protocol = tdGetProtocol( id ); tdName2Id[*name]=id; strcpy(ts_aliases,"ALIAS='"); strcat(ts_aliases,name); strcat(ts_aliases,"'\nPROTOCOL='"); strcat(ts_aliases,protocol); strcat(ts_aliases,"' >> "); printf("%d\t%s\t%s\t%i\n", id, name, protocol,tdName2Id[*name]); tdReleaseString(name); tdReleaseString(protocol); }

Det var ett tag sedan jag skrev denna kod (har återupptagit projektet nyss), och jag vet att tanken är att skapa en char (ts_aliases) som innehåller något i stil med:

ALIAS='Lampa'\nPROTOCOL='NEXA'\nALIAS='Soffa'\nPROTOCOL=NEXA >>

Den delen fungerar som den ska, men sen finns det en del som skall fylla tdName2Id med information
Tanken var att jag skulle kunna anropa tdName2Id med en text, tex "Lampa" och sedan returnerar den en int

Tänk er: (denna information ligger lagrad på servern)
id namn protocol
1 Lampa NEXA
2 Soffa NEXA

Om servern får som svar av klienten (klienten har inte jag gjort, så jag kan inte be den skicka id istället) att den skall tända lampan "Soffa", då vill jag att servern ska förstå att "Soffa" är lampan med id 2. Hänger ni med?

Är jag ute och cyklar med min kod ovanför? Hur skulle ni gjort?

MVH Niclas

edit: ser nu att med raden:

printf("%d\t%s\t%s\t%i\n", id, name, protocol,tdName2Id[*name]);

så får jag ju fram id från tdName2Id[*name]
Men om jag klipper ut den raden och lägger den utanför for-loopen så verkar jag inte få "tag" på informationen som är lagrad i den. Typ att den inte är global? Går fortfarande bet på det alltså :/

Permalänk

Jag är inte helt hundra på hur du tänker att det ska fungera, men utifrån din beskrivning så kanske det här gör vad du vill:

#include <string> #include <vector> using namespace std; struct TelldusDevice { int m_id; string m_name; string m_protocol; }; vector<TelldusDevice> EnumerateDevices() { vector<TelldusDevice> devices; int numberOfDevices = tdGetNumberOfDevices(); for (int i = 0; i < numberOfDevices; i++) { int id = tdGetDeviceId(i); char* name = tdGetName(id); char* protocol = tdGetProtocol(id); TelldusDevice device = { id, name, protocol }; devices.push_back(device); tdReleaseString(protocol); tdReleaseString(name); } return devices; } int FindDeviceId(const vector<TelldusDevice>& devices, const string& name) { for (unsigned int i = 0; i < devices.size(); i++) { if (devices[i].m_name == name) return devices[i].m_id; } return -1; } void main() { vector<TelldusDevice> devices = EnumerateDevices(); // ... int soffaId = FindDeviceId(devices, "Soffa"); int lampaId = FindDeviceId(devices, "Lampa"); }

Du kör alltså EnumerateDevices en gång tidigt i programmet för att alla inkopplade enheter ska hittas, och sen FindDeviceId för varje gång som du vill hitta ett id som motsvarar ett namn. Ifall det inte finns någon enhet som motsvarar ett namn så returneras -1 från FindDeviceId.

Permalänk
Medlem

VirtualIntent: Du förstod att det hade med Telldus Tellstick att göra, har du gjort något eget program för det?

Jag har en sak som är kvar innan jag kan känna mig någolunda klar och kan börja snygga till allt.
Det är så att jag skulle behöva göra så att allt som skickas är kodat med ISO 8859-1. Just nu så blir tex "Vintrinskåp": Vintrinsk(tecknet för roten ur å sen en punkt)p

Har försökt leta på google men tycker inte att jag hittar något som jag förstår :/

Nån som kan ge mig lite hjälp på vägen?

MVH Niclas

Permalänk
Skrivet av skorpion:

VirtualIntent: Du förstod att det hade med Telldus Tellstick att göra, har du gjort något eget program för det?

Nej jag har inte gjort något program utan jag googlade på anropen du gjorde och såg att de var funktioner i APIet från Telldus.

Skrivet av skorpion:

Jag har en sak som är kvar innan jag kan känna mig någolunda klar och kan börja snygga till allt. Det är så att jag skulle behöva göra så att allt som skickas är kodat med ISO 8859-1. Just nu så blir tex "Vintrinskåp": Vintrinsk(tecknet för roten ur å sen en punkt)p

Har försökt leta på google men tycker inte att jag hittar något som jag förstår :/

Varifrån tar du emot strängen och vilken kodning har den? Till var ska du skicka eller skriva ut strängen, och vilken kodning förväntas den ha då?