Socket programmeren

Status
Niet open voor verdere reacties.

janmulder13

Gebruiker
Lid geworden
15 sep 2009
Berichten
43
Hallo,
Ik heb een probleem met socket programmeren. Ik programmeer veel voor de Nintendo DS (in C) en ik probeer nu om een verbinding via WiFi naar een ander Nintendo DS systeem te leggen. Dit probeer ik te doen via mijn eigen computer door daar weer een programmaatje op te laten draaien (ik dacht dat het zo moest, ik weet het niet zeker).

Dit is wat ik in dat programmaatje heb staan:
Code:
#include <cstdlib>
#include <iostream>
#include <WinSock.h>
#include <wininet.h>
#include <stdio.h>
#include <string.h>


char *getwebpage(char *hostname, char *uri, unsigned long *total)
{
	if(!hostname || !uri || !total) return (char *)0;
	*total = 0;
	
	char *headers1 = "Accept: text/html, */*\nAccept-Language: en-gb\nAccept-Encoding: none\nHost: ";
	char *headers2 = (char *)malloc(strlen(headers1) + strlen(hostname) + 2);
	sprintf(headers2, "%s%s\n", headers1, hostname);
	HINTERNET session = InternetOpen("Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
	HINTERNET connect = InternetConnect(session, hostname, 80, "", "", INTERNET_SERVICE_HTTP, 0, 0);
	HINTERNET http	= HttpOpenRequest(connect, "GET", uri, HTTP_VERSION, NULL, 0, INTERNET_FLAG_DONT_CACHE, 0);
	HttpSendRequest(http, headers2, strlen(headers2), NULL, 0);
	free(headers2);
	
	unsigned long read;
	char buffer[1024];
	char *final = (char *)malloc(1024);
	memset(buffer, 0, 1024);
	memset(buffer, 0, 1024);
	while(InternetReadFile(http, buffer, 1024, &read) && (read != 0)){
		CopyMemory((final + *total), buffer, read);
		*total += read;
		final = (char *)realloc(final, (*total + 1024));
		memset((final + *total), 0, 1024);
	}
	
	InternetCloseHandle(http);
	InternetCloseHandle(connect);
	InternetCloseHandle(session);
	
	return final;
}

int getmyipaddress(char *buffer)
{
	unsigned long length;
	char *webpage = getwebpage("www.ipchicken.com", "/", &length);
	if(!webpage || length == 0) return 0;
	int result = 0;
	char *start = strstr(webpage, "<b>");
	if(start){
		start += 3;
		while(*start <= ' ') start++;
		char *end = start;
		while(*end > ' ') end++;
		*end = 0;
		strcpy(buffer, start);
		result = 1;
	}
	free(webpage);
	return result;
}

using namespace std;

#define MIJNPOORT   8888


int main(void) {
    char IPAddr[15];
    getmyipaddress(IPAddr);
    cout << "IP: " << IPAddr << "\n";
    char players;
    char cplay[5];
    int sock[2] = {-1,-1};
    int eigensock;
    struct sockaddr_in Zelf, Ander[2];
    Zelf.sin_family = AF_INET;
	Zelf.sin_port = htons(MIJNPOORT);
	Zelf.sin_addr.s_addr = inet_addr(IPAddr);
	memset(&(Zelf.sin_zero),'\0',8);
	eigensock = socket(AF_INET, SOCK_STREAM, 0); 
	itoa(ntohs(Zelf.sin_port),cplay,10);
    cout << "Port: " << cplay << "\n";
	cout << "created a socket\n";
	bind(eigensock, (struct sockaddr *)&Zelf, sizeof(struct sockaddr));
	cout << "binded\n";
	char count1 = 0;
	char count2 = 0;
	int size;
	int len = 0;
	char buffer[512];
	while (true) {
		listen(eigensock, 20);
		size = sizeof(struct sockaddr_in);
		sock[players] = accept(eigensock, (struct sockaddr *)&Ander[players], &size);
		if (sock[players] >= 0) {
           players++;
           itoa(players,cplay,10);
           cout << "accepted " << cplay << " players\n";
        }
		for(count1=0;count1<players;count1++) {
			len = recv(sock[count1],buffer,512,0);
			if (len == 0) {
               players = 0;
               sock[0] = -1;
               sock[1] = -1;
               cout << "disconnected\n";
            }
			for(count2=0;count2<players;count2++) {
				if (count2 != count1) send(sock[count2],buffer,len,0);
			}
		}
	}
	return 0;
}

het compileert zonder fouten. Wat ik dus eigenlijk wilde doen is connect()en met de Nintendo DS naar het IP adres van mijn computer + de poort die ik invul. Zodat het programmaatje dat dan weer naar de andere spelers kan doorsturen.

De Nintendo DS geeft echter een fout aan in connect() (na socket() en bind()). 'errno' is gelijk aan 113 ("no route to host"). Ik dacht dat dit misschien aan de poort zou liggen, maar het zou ook zomaar iets anders kunnen zijn.

Zijn er hier mensen met verstand van dit soort dingen?

Alvast bedankt,

Jan.

PS: Ja, ik weet dat het niet zo heel efficient geprogrammeerd is, maar ik wil misschien nog meer dan 2 spelers toe gaan laten.
 
Laatst bewerkt:
Als je je server bind() moet je het loopback adres gebruiken: 127.0.0.1
 
Heb ik ook al geprobeerd, maar het werkt niet. Het zegt dan ook errno = 113, "no route to host".

Dit zijn de functies die ik heb geschreven voor de client kant (op de Nintendo DS):
Code:
struct sockaddr_in WiFiLibAddr, WiFiLibAddr2;

int FirstStep(char *IP, unsigned short int Port) {
	WiFiLibAddr.sin_family = AF_INET;
	WiFiLibAddr.sin_port = htons(Port);
	if (inet_addr(IP) == -1) return -1;
	WiFiLibAddr.sin_addr.s_addr = inet_addr(IP);
	memset(&(WiFiLibAddr.sin_zero), '\0', 8);
	WiFiLibSock = socket(AF_INET, SOCK_STREAM, 0);
	if (WiFiLibSock == -1) return -2;
	return 0;
}

int SecondStep(void) {
	return bind(WiFiLibSock, (struct sockaddr *)&WiFiLibAddr, sizeof(struct sockaddr));
}
	
int ThirdStep(void) {
	return connect(WiFiLibSock, (struct sockaddr *)&WiFiLibAddr, sizeof(struct sockaddr));
}

int Connect(char *IP, unsigned short int Port) {
	int err;
	err = FirstStep(IP, Port);
	if (err < 0) return err;
	err = SecondStep();
	if (err < 0) return (err-2);
	err = ThirdStep();
	if (err < 0) return (err-3);
	return 0;
}

Voor IP gebruik ik het externe IP adres van mijn computer en voor Port dezelfde als MIJNPOORT in de computer applicatie.

Iemand een idee?
 
Ja, nu heb ik zeker een idee wat er fout gaat. Als je het externe ip gebruikt moet je eerst de poort forwarden in je router opties. Je kunt beter je ip binnen je lan gebruiken. Type 'ipconfig' in de commandline en daar staat ie ergens, hij ziet er ws ongeveer zo uit: 192.168.1.?? of 192.168.1.?? of 10.0.?.? Pas op dat je niet de router gateway adres gebruik, maar het ip adres van je pc!

Als je je DS connect met dat ip en je pc bind met het loopback adres zou het moeten lukken. :)
 
Ja, maar dat IP adres werkt niet als de DS zich niet in hetzelfde netwerk als de computer bevindt. Enig idee hoe ik de poort 'forward'?
 
Dat verschild per router, op deze website vind je een lijst van routers, selecteer je router, klik rechtsbovenin op 'Skip this advertisment' en zoek naar de link met 'Default guide'. Als je daar op klikt krijg je een uitgebreide tut over hoe je die port kan forwarden. Je moet het forwarden naar de computer waar dat programmatje draait natuurlijk. :)
 
Ik weet niet wat jij in je gedachten hebt over C, maar dit is zeker geen C...
 
Ik heb besloten om in plaats van de computer applicatie een server te maken op internet (aangezien computer niet altijd online is). Dus met PHP. Welke poort moet ik dan gebruiken of maakt dat niet uit?
 
Ik weet niet wat jij in je gedachten hebt over C, maar dit is zeker geen C...

Als je het hebt over het router configureren heb je gelijk, het is geen C. Maar elke router blokkeert standaard alle inkomende verbindingen van buitenaf, tenzij je een Port Forwarding rule opzet die de verbinding doorstuurt naar één van de computers binnen het netwerk. Als je het hebt over de code van janmulder dan heb je geen gelijk, dat is echt C.

Ik heb besloten om in plaats van de computer applicatie een server te maken op internet (aangezien computer niet altijd online is). Dus met PHP. Welke poort moet ik dan gebruiken of maakt dat niet uit?

In PHP gebruik je dezelfde functies als in C (lijst van socket functies in PHP), de poort maakt dus niet uit. Maar let wel op dat jouw hosting provider het gebruik van sockets in PHP ondersteund, veel hosting providers doen dat niet!
 
Ik ben niet erg goed in PHP, daarom heb ik het nog een keer geprobeerd met C. Dit is wat ik heb voor de server:
Code:
#include <cstdlib>
#include <iostream>
#include <WinSock.h>
#include <wininet.h>
#include <stdio.h>
#include <string.h>

using namespace std;

#define POORT   4041
#define MAXDATA 512

void printos(char *text) {
     cout << text;
}

void stop(void) {
     system("PAUSE");
}

void setgrootstesocket(int gs, int sockfd) {
     if (sockfd > gs) gs = sockfd;
}

void printno(int no) {
     char number[10];
     itoa(no,number,10);
     printos(number);
     printos("\n");
}

int main(void) {
    fd_set AllDS;
    FD_ZERO(&AllDS);
    fd_set ReadDS;
    FD_ZERO(&ReadDS);
    fd_set WriteDS;
    FD_ZERO(&WriteDS);
    int eigensocket;
    int buffersocket;
    char buffer[MAXDATA];
    int err;
    int grootstesocket;
    struct sockaddr_in mijnadres;
    struct sockaddr_in anderadres;
    struct timeval maxwachttijd;
    maxwachttijd.tv_sec = 10;
    maxwachttijd.tv_usec = 0;
    int i, j;
    int adreslengte;
    int aantalbytes;
    
    mijnadres.sin_family = AF_INET;
    mijnadres.sin_addr.s_addr = inet_addr("192.168.1.20");
    mijnadres.sin_port = htons(POORT);
    memset(&(mijnadres.sin_zero), '\0', 8);
    
    WSADATA t_wsa;
    WORD wVers;
    wVers = MAKEWORD(2, 2);
    WSAStartup(wVers, &t_wsa);
    
    eigensocket = socket(AF_INET, SOCK_STREAM, 0);
    if (eigensocket == -1) {
                  printos("socket fout\n");
                  printno(WSAGetLastError());
                  stop();
    }else{
          printos("socket ok\n");
    }
    
    err = bind(eigensocket, (struct sockaddr *)&mijnadres, sizeof(mijnadres));
    if (err == -1) {
            printos("bind fout\n");
            stop();
    }else{
          printos("bind ok\n");
    }
    
    err = listen(eigensocket, 10);
    if (err == -1) {
            printos("listen fout\n");
            stop();
    }else{
          printos("listening...\n");
    }
    FD_SET(eigensocket, &AllDS);
    setgrootstesocket(grootstesocket,eigensocket);
    while (true) {
          ReadDS = AllDS;
          err = select(grootstesocket+1, &ReadDS, NULL, NULL, NULL);
          if (err == -1) {
                  printos("select fout\n");
                  stop();
          }
          for (i=0;i<=grootstesocket;i++) {
              if (FD_ISSET(i, &ReadDS)) {
                              if (i == eigensocket) {
                                    adreslengte = sizeof(anderadres);
                                    buffersocket = accept(eigensocket, (struct sockaddr *)&anderadres, &adreslengte);
                                    if (buffersocket == -1) {
                                                     printos("accept fout\n");
                                    }else{
                                          FD_SET(buffersocket, &AllDS);
                                          setgrootstesocket(grootstesocket,buffersocket);
                                    }
                              }else{
                                    aantalbytes = recv(i, buffer, sizeof(buffer), 0);
                                    if (aantalbytes <= 0) {
                                            if (aantalbytes == 0) {
                                                    printos("disconnected\n");
                                            }else{
                                                  printos("disconnected\n");
                                            }
                                            closesocket(i);
                                            FD_CLR(i, &AllDS);
                                            FD_CLR(i, &ReadDS);
                                    }else{
                                          printos(buffer);
                                          printos("\n");
                                          for (j=0;j<=grootstesocket;j++) {
                                              if (FD_ISSET(j, &AllDS)) {
                                                              if (j != eigensocket && j != i) {
                                                                    err = send(j, buffer, aantalbytes, 0);
                                                                    if (err == -1) {
                                                                            printos("send fout");
                                                                    }
                                                              }
                                              }
                                          }
                                    }
                              }
              }
          }
    }
	return 0;
}

en dit voor de client:
Code:
#include <cstdlib>
#include <iostream>
#include <WinSock.h>
#include <wininet.h>
#include <stdio.h>
#include <string.h>

using namespace std;

#define POORT   4041

void printos(char *text) {
     cout << text;
}

void stop(void) {
     system("PAUSE");
}

void printno(int no) {
     char number[10];
     itoa(no, number, 10);
     printos(number);
     printos("\n");
}

int main(void) {
    char DataToSend[512] = "Hi Server";
    char ReceivedData[512];
    memset(ReceivedData,'\0',512);
    struct sockaddr_in anderadres;
    anderadres.sin_family = AF_INET;
    anderadres.sin_port = htons(POORT);
    anderadres.sin_addr.s_addr = inet_addr("192.168.1.20");
    memset(&(anderadres.sin_zero), '\0', 8);
    WSADATA t_wsa;
    WORD wVers;
    wVers = MAKEWORD(2, 2);
    WSAStartup(wVers, &t_wsa);
    int eigensocket;
    int err;
    eigensocket = socket(AF_INET, SOCK_STREAM, 0);
    if (eigensocket == -1) {
                    printos("socket fout\n");
                    stop();
    }else{
          printos("socket ok\n");
    }
    
    err = connect(eigensocket, (struct sockaddr *)&anderadres, sizeof(struct sockaddr));
    if (err == -1) {
            printos("connect fout\n");
            printno(WSAGetLastError());
            stop();
    }else{
          printos("connect ok\n");
    }
    printos("sending and receiving...");
    int len;
    while (true) {
          ReceivedData[0] = '\0';
          send(eigensocket,DataToSend,strlen(DataToSend),0);
          len = recv(eigensocket,ReceivedData,512,0);
          cout << ReceivedData;
    }
return 0;
}

Op deze manier werkt het perfect, maar dit is over LAN (lokaal). Ik wil dat hij werkt over WAN (internet). Echter, als ik bij de client mijn externe IP adres invul dan geeft WSAGetLastError() 10061 terug (Connection Refused). Ik heb echter de poort (4041) opengemaakt in mijn router en firewall.

Heeft iemand een idee hoe ik dit oplos?

Alvast bedankt.
 
Het ziet er allemaal goed uit, weet je zeker dat je de poort in je router hebt geforeward naar de goede LAN-ip? In de meeste routers zit standaard een DHCP server ingeschakeld die automatisch ip adressen uitdeeld, op een netwerk met meerdere apparaten zul je zien dat het LAN-ip daarom om de zoveel tijd veranderd (standaard verloopt ie na 24u volgensmij).

Je kunt natuurlijk elke keer dat dat gebeurd de LAN-ip in je router configuratie bij het port forwarden weer veranderen maar dat kost veel tijd. Daarom kan je het beste je computer een statisch ip adres geven, hiermee omzijl je de DHCP server.

Hier is een goeie tut over hoe dat gaat in Windows, let wel op dat je alles goed insteld!
Assign Static IP Address
(Windows XP)
- voor Vista is ongeveer hetzelfde, Windows 7 weet ik niet maar denk het wel.
 
Bedankt voor je antwoord. Ik heb al een statisch IP adres. En ik weet inmiddels ook al dat het niet aan de server en het openen van de poort ligt. Aan de client kant is er iets fout. Ik heb echter geen idee wat.
 
WSAECONNREFUSED (10061) Connection refused
No connection could be made because the target machine actively refused it.

Dit betekent dus dat de server de verbinding heeft geweigerd, het feit dat het wel werkt binnen de LAN wijst er ook op dat het iets heeft te maken met een firewall. Probeer anders eens dmv debuggen of je server iets binnen krijgt, komt de accept() functie aan bod, en kijk of die misschien fouten produceerd.
 
De server blijkt te werken, want met deze site kan ik dat zien: http://canyouseeme.org/. Mijn server geeft dan aan 'disconnected', dus ik weet dat hij verbinding heeft gehad. Door de 'netstat -a' te gebruiken in cmd.exe kan ik zien dat hij ook daadwerkelijk aan het luisteren is. Wat wel erg vreemd is, is dat wanneer ik ze over LAN verbind. Dan staat er in 'netstat -a' dit:
Code:
lokaal adres:        extern adres:
192.168.1.20:4041    JAN-PC:[b]....[/b]    ESTABLISHED
op de .... staat een (volgens mij) 'random' poort nummer. Dat zou verklaren dat hij niet over de WAN kan verbinden.
 
Dat er bij de client een willekeurige poort staat is normaal, voor de verbinding is alleen de poort van de server van belang.

Alles wijst nog steeds op een fout geconfigureerde firewall, kan je een printscreen sturen van je router port forwarding page?
 
PortForwarding.png

Ik moet een externe poort opgeven. Dit is 4041 in de client, maar als de client een willekeurige poort gaat aannemen dan werkt het natuurlijk niet meer. :confused:
 
Ow vandaar :shocked:, meeste routers vragen alleen naar een interne port.

Je kunt net als je bij een server moet doen, ook een client bind()en. Bind() je client aan de goeie poort en geef ook het lokale LAN-ip op van de client. Oja, en wel binden voor de connect() call. Als je connect() gebruikt zonder te bind()en, kiest Windows zelf een poort uit de 'dynamic port range', dit is normaal en ook aangeraden omdat je client anders met bepaalde andere programma's in de war kan raken. Maar in jouw geval zal je wel moeten. :P

Meer uitleg over de functie bind() en het verhaal hierboven.
 
Hardstikke bedankt! Dat lijkt me het probleem. Ik ga nu eerst lekker slapen, dan test ik het morgen :).
 
Helaas, nog steeds zelfde fout. Ik moet hem wel op een andere computer testen, want anders zegt hij dat het adres al in gebruik is. Dan run ik hem op de andere computer en dan krijg ik de wel bekende zelfde 10061 (Connection Refused).

code van de client:
Code:
#include <cstdlib>
#include <iostream>
#include <WinSock.h>
#include <wininet.h>
#include <stdio.h>
#include <string.h>



using namespace std;

#define POORT   50505

void printos(char *text) {
     cout << text;
}

void stop(void) {
     system("PAUSE");
}

void printno(int no) {
     char number[10];
     itoa(no, number, 10);
     printos(number);
     printos("\n");
}

int main(void) {
    char DataToSend[512] = "Hi Server";
    char ReceivedData[512];
    memset(ReceivedData,'\0',512);
    WSADATA t_wsa;
    WORD wVers;
    wVers = MAKEWORD(2, 2);
    WSAStartup(wVers, &t_wsa);
    struct sockaddr_in anderadres, mijnadres;
    anderadres.sin_family = AF_INET;
    anderadres.sin_port = htons(POORT);
    anderadres.sin_addr.s_addr = inet_addr("87.209.54.39");
    memset(&(anderadres.sin_zero), '\0', 8);
    mijnadres.sin_family = AF_INET;
    mijnadres.sin_port = htons(POORT);
    mijnadres.sin_addr.s_addr = INADDR_ANY;
    memset(&(mijnadres.sin_zero), '\0', 8);
    int eigensocket;
    int err;
    eigensocket = socket(AF_INET, SOCK_STREAM, 0);
    if (eigensocket == -1) {
                    printos("socket fout\n");
                    stop();
    }else{
          printos("socket ok\n");
    }
    err = bind(eigensocket, (struct sockaddr *)&mijnadres, sizeof(mijnadres));
    if (err == -1) {
            printos("bind fout\n");
            printno(WSAGetLastError());
            stop();
    }else{
          printos("bind ok\n");
    }
    
    err = connect(eigensocket, (struct sockaddr *)&anderadres, sizeof(struct sockaddr));
    if (err == -1) {
            printos("connect fout\n");
            printno(WSAGetLastError());
            stop();
    }else{
          printos("connect ok\n");
    }
    printos("sending and receiving...");
    int len;
    while (true) {
          ReceivedData[0] = '\0';
          send(eigensocket,DataToSend,strlen(DataToSend),0);
          len = recv(eigensocket,ReceivedData,512,0);
          cout << ReceivedData;
    }
return 0;
}
 
Status
Niet open voor verdere reacties.

Nieuwste berichten

Terug
Bovenaan Onderaan