send() vertragen.

Status
Niet open voor verdere reacties.

janmulder13

Gebruiker
Lid geworden
15 sep 2009
Berichten
43
Ik heb een server geschreven voor op mijn PC. De clients zijn echter Nintendo DS-en (ik programmeer voor Nintendo DS). Dit werkt nu bijna helemaal perfect op een klein detail na. De DS kent geen non-blocking sockets dus moet er altijd wat naar de DS verzonden worden om recv() niet te laten blocken. Als er slechts een client verbonden is moet er dus constant iets naar de Nintendo DS verzonden worden. Een Nintendo DS werkt met maar 60 frames per seconde, dus hij checkt recv() "maar" 60 keer per seconde. Als ik mijn computer echter elk frame iets laat verzenden dan gaat dat veeeeel te snel voor de DS. Dat wordt dan opgestapeld en de DS moet dan veel meer ontvangen. Hierdoor vertraagt de DS.

Ik vraag me af of het mogelijk is om mijn computer slechts 60 keer per seconde iets te laten verzenden zonder dat de rest vertraagt van het programma vertraagt. Óf of het mogelijk is om de DS de te laten stoppen met recv()en na MAXDATA bytes hoewel er nog heel veel "in de rij" staat.

Hieronder is de code van mijn PC server:

Code:
#include <cstdlib>
#include <iostream>
#include <WinSock.h>
#include <wininet.h>
#include <stdio.h>
#include <string.h>

using namespace std;

#define POORT   50505
#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");
}

void printnowe(int no) {
     char number[10];
     itoa(no,number,10);
     printos(number);
}

int main(void) {
    fd_set AllDS;
    FD_ZERO(&AllDS);
    fd_set ReadDS;
    FD_ZERO(&ReadDS);
    int players = 0;
    int eigensocket;
    int buffersocket;
    char buffer[MAXDATA];
    int err;
    int grootstesocket=0;
    struct sockaddr_in mijnadres;
    struct sockaddr_in anderadres;
    struct timeval maxwachttijd;
    maxwachttijd.tv_sec = 0;
    maxwachttijd.tv_usec = 1000000/60;
    int i, j;
    int adreslengte;
    int aantalbytes;
    u_long nonblock = 1;
    mijnadres.sin_family = AF_INET;
    mijnadres.sin_addr.s_addr = INADDR_ANY;
    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);
    
    bool yes = true;
    setsockopt(eigensocket, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(int));
    
    if (eigensocket == -1) {
                  printos("socket fout\n");
                  printno(WSAGetLastError());
                  stop();
    }else{
          printos("socket ok\nsocket number: ");
          printno(eigensocket);
    }
    
    err = bind(eigensocket, (struct sockaddr *)&mijnadres, sizeof(mijnadres));
    if (err == -1) {
            printos("bind fout\n");
            printno(WSAGetLastError());
            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);
    grootstesocket = eigensocket;
    while (true) {
          ReadDS = AllDS;
          err = select(grootstesocket+1, &ReadDS, NULL, NULL, &maxwachttijd);
          if (err == -1) {
                  printos("select fout\n");
                  stop();
          }
if (FD_ISSET(eigensocket, &ReadDS)) {
                                   adreslengte = sizeof(anderadres);
                                   printos("accepting...\n");
                                   buffersocket = accept(eigensocket, (struct sockaddr *)&anderadres, &adreslengte);
                                   if (buffersocket == -1) {
                                                    printos("accept fout\n");
                                   }else{
                                         printos("connected to: ");
                                         printos(inet_ntoa(anderadres.sin_addr));
                                         printos("\n");
                                         players++;
                                         printos("players: ");
                                         printno(players);
                                         ioctlsocket(buffersocket,FIONBIO,&nonblock);
                                         FD_SET(buffersocket, &AllDS);
                                         if (buffersocket>grootstesocket) grootstesocket = buffersocket;
                                   }
          }
          for (i=0;i<=grootstesocket;i++) {

              if (players == 1 && i != eigensocket && FD_ISSET(i, &AllDS)) {
                          
                          memset(&buffer[0],0,MAXDATA);
                          strncpy(&buffer[MAXDATA-4],(char*)&players,4);
                          send(i,buffer,MAXDATA,0);

              }
              if (FD_ISSET(i, &ReadDS) && i != eigensocket) {
                              adreslengte = sizeof(anderadres);
                              getpeername(i, (struct sockaddr *)&anderadres, &adreslengte);
                              printos("receiving...");
                              aantalbytes = recv(i,buffer,sizeof(buffer),0);
                              if (aantalbytes <= 0) {
                                              printos("disconnected from: ");
                                              printos(inet_ntoa(anderadres.sin_addr));
                                              printos("\n");
                                              closesocket(i);
                                              FD_CLR(i, &AllDS);
                                              players--;
                                              printos("players left: ");
                                              printno(players);
                              }else{
                                    printos("received ");
                                    printnowe(aantalbytes);
                                    printos(" bytes from: ");
                                    printos(inet_ntoa(anderadres.sin_addr));
                                    printos("\n");
                                    strncpy(&buffer[MAXDATA-4],(char*)&players, 4);
                                    for (j=0;j<grootstesocket;j++) {
                                        if (j != i && j != eigensocket && FD_ISSET(j, &AllDS)) {
                                              send(j, buffer, MAXDATA, 0);
                                        }
                                    }
                              }
                        
              }
          }
    }
	return 0;
}

Alvast bedankt!
 
Laatst bewerkt:
Ik denk dat je uberhaupt niet een programma moet willen schrijven dat 60 keer per seconde een pakketje verstuurd. Hoewel dit binnen je LAN nog niet een probleem is, wordt dat het zeker wel wanneer je deze programma's in het echt gaat gebruiken. Door de vertraging tussen de computers zal je niet de exacte timing behalen van het verzenden. Hierdoor gaat de DS juist weer achterlopen of je krijgt 'lag' omdat de DS te snel is voor de server.

Je kan beter een extra thread in je DS programma starten om het non-blocking effect na te spelen, of is er ook geen thread mogelijkheid in je DS library?
 
Ok. Ik bedacht me net of er misschien een flag is voor recv die zorgt dat hij niet blockt. De DS werkt nog met sys/socket niet met winsock, trouwens.

Ik doe al best wel een tijdje dit programmeren en ik kan best veel doen met C. Maar ik moet eerlijk bekennen dat ik nog nooit van de term threads heb gehoord... :S
 
Ik dacht dat sys/sockets ook non-blocking sockets kende. Lees anders voor een hele complete tutorial over socket programmeren dit eens: Beej's Guide to Network Programming

Als engels een beetje tegenvalt is er vast en zeker ook nog wel een Nederlandse versie van de tutorial.

Threads zijn eigenlijk verschillende lijnen binnen een programma. Veronderstel dat je een programma hebt dat eerst een groot bestand moet lezen, en de data daaruit moet verwerken, om ze vervolgens te presenteren op het scherm. Als deze drie taken kosten veel tijd, in een programma met 1 thread zul je eerst de data moet lezen, het daarna verwerken, en daarna tekenen op het scherm. Maar stel nou dat je 3 threads neemt, de eerste begint met het lezen en stuurt de resultaten 'live' door naar thread 2 die de data verwerkt en op zijn beurt deze informatie ook doorstuurt naar thread 3 die de gegevens tekent. Dan gebruikt je 3x zo weinig tijd en is je programma ook nog overzichtelijker.

Je kunt threads dus zijn als programma's binnen programma's, alleen dan delen ze wel informatie. Dit kan wel voor problemen zorgen, als thread 2 bijvoorbeeld een stukje info van thread 1 leest, terwijl thread 1 op het zelfde moment ook de informatie schrijft op dat stukje kan je programma crashen. Daarom moet je bij threads gedeelde informatie altijd thread-safe maken. Voor een uitgebreidere uitleg zou ik ff Googlen :)
 
Laatst bewerkt:
Het is een vreemde versie van sys/sockets, want fcntl werkt niet. Gelukkig heb ik het toch op weten te lossen met de functie ioctl die wel blijkt te werken.

Toch bedankt voor de moeite.
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan