Avatar billede quiw Nybegynder
09. januar 2006 - 10:10 Der er 19 kommentarer og
1 løsning

Multithreaded server.

Hej Igen Eksperten ..
- Nu har jeg umiddelbart leget lidt med multithreading ... Og har brygget et stykke kode sammen, som i sidste ende gerne skulle ligne en multithreaded server.
- Jeg har sat den til at loope acceptere connections. Men umiddelbart virker det ikke..
Har 2 spørgsmål:
#1 - Den siger fejl ved P "undeclared"
#2 - Ser min kode fornuftig ud som helhed?
Min kode ser sådan her ud:

#include <iostream>

using namespace std;

#include <windows.h>

DWORD __stdcall ThreadFunc(void *lpParameter)
{
  DWORD MainThread = (DWORD )lpParameter;

            p=(char *)&cmd;
            ix=0;
           
            messages="Welcome Online! \n";
            send(sd2, messages, strlen(messages),0);

while((len=recv(sd2,p+ix,1,0))>0) // Modtager tegn i array
            {
                  ix=ix+len;
                  if(cmd[ix-1]=='\n')
                  {
                                // Commands start:
                                cmd[ix-1]='\0';
                               
                                if(cmd[strlen(cmd)-1]=='\r')cmd[strlen(cmd)-1] = '\0';
                                ix=0;
                               
                                messages="<console> ";
                                send(sd2, messages, strlen(messages),0);
                               
                                if ( strcmpi ( cmd,"quit") == 0 )
                                {
                                              messages="Aight, Goodbye ! :) \n";
                                              send(sd2, messages, strlen(messages),0);
                                              goto fin;
                                }
                                else
                                {
                                              messages="Unknown Command \n";
                                              send(sd2, messages, strlen(messages),0);
                                }
                  }
            }
  PostThreadMessage (MainThread, 1000, 0, 0);
  return 0;
}


int main()
{
    int online = 1;
    while (online==1)
    {
            WSADATA WSAData;
            int sd,sd2,status,len,ix;
            char cmd[100],*p;
            char* messages;
            char buf[2000];
            struct sockaddr_in local;
            WSAStartup(0x0101,&WSAData); //WSA Startup
            sd=socket(AF_INET,SOCK_STREAM,0); // Skaber Socket
            if(sd<0)
            {
                printf("Kunne ikke skabe socket: %s\n",strerror(errno));
                goto fin;
            }
            local.sin_family=AF_INET; //Binder socket
            local.sin_port = htons(1234); // Binder socket til port nummer 1234
            local.sin_addr.s_addr = INADDR_ANY; // Binder socket til local IP
            status=bind(sd,(struct sockaddr *)&local,sizeof(local));
            if(status<0)
            {
                  printf("Kunne ikke binde socket: %s\n",strerror(errno));
            }
            status=listen(sd,5); // Lyttende Socket
            if(status<0)
            {
                  printf("Kunne ikke lytte til socket: %s\n",strerror(errno));
            }
            sd2=accept(sd,0,0); // Acceptere Connections
            if(sd2<0)
            {
                  printf("Kunne ikke acceptere socket: %s\n",strerror(errno));
            }
  DWORD ThreadId;
  DWORD MainThreadId = GetCurrentThreadId();
  cout << "Start thread" << std::endl;
  CreateThread(0, 0, ThreadFunc, (LPVOID )MainThreadId, 0, &ThreadId);
  }
  cout << "Thread started" << std::endl;
                  :fin
                  closesocket(sd2); // Lukker SD2 Socket
                  closesocket(sd); // Lukker SD Socket
                  WSACleanup(); //WSA Cleanup
                  goto start;
  system("Pause");
  return 0;
}

- Kunne godt tænke mig at få min kode til at  virke.
På Forhånd Tak.
Avatar billede quiw Nybegynder
09. januar 2006 - 10:17 #1
Hov .. Har selv fundet svaret på mit første spørgsmål .. Havde glemt at sætte variablerne ind .. Og har ændret lidt i koden .. Så den kan godt compiles .. Men når jeg kører mit program bliver den helt vild og skriver "kunne ikke lytte til socket.. Kunne ikke starte socket .." når man prøver at connecte.
Min kode ser nu sådan her ud:

#include <iostream>

using namespace std;

#include <windows.h>

DWORD __stdcall ThreadFunc(void *lpParameter)
{
  DWORD MainThread = (DWORD )lpParameter;
            int sd,sd2,status,len,ix;
            char cmd[100],*p;
            p=(char *)&cmd;
            ix=0;
            char* messages;
            char buf[2000];
           
            messages="Welcome Online! \n";
            send(sd2, messages, strlen(messages),0);

while((len=recv(sd2,p+ix,1,0))>0) // Modtager tegn i array
            {
                  ix=ix+len;
                  if(cmd[ix-1]=='\n')
                  {
                                // Commands start:
                                cmd[ix-1]='\0';
                               
                                if(cmd[strlen(cmd)-1]=='\r')cmd[strlen(cmd)-1] = '\0';
                                ix=0;
                               
                                messages="<console> ";
                                send(sd2, messages, strlen(messages),0);
                               
                                if ( strcmpi ( cmd,"quit") == 0 )
                                {
                                              messages="Aight, Goodbye ! :) \n";
                                              send(sd2, messages, strlen(messages),0);
                                              closesocket(sd2); // Lukker SD2 Socket
                                              closesocket(sd); // Lukker SD Socket
                                              WSACleanup(); //WSA Cleanup
                                             
                                }
                                else
                                {
                                              messages="Unknown Command \n";
                                              send(sd2, messages, strlen(messages),0);
                                }
                  }
            }
  PostThreadMessage (MainThread, 1000, 0, 0);
  return 0;
}


int main()
{
    int online = 1;
    while (online==1)
    {
            WSADATA WSAData;
            int sd,sd2,status,len,ix;
            char cmd[100],*p;
            char* messages;
            char buf[2000];
            struct sockaddr_in local;
            WSAStartup(0x0101,&WSAData); //WSA Startup
            sd=socket(AF_INET,SOCK_STREAM,0); // Skaber Socket
            if(sd<0)
            {
                printf("Kunne ikke skabe socket: %s\n",strerror(errno));
            }
            local.sin_family=AF_INET; //Binder socket
            local.sin_port = htons(1234); // Binder socket til port nummer 1234
            local.sin_addr.s_addr = INADDR_ANY; // Binder socket til local IP
            status=bind(sd,(struct sockaddr *)&local,sizeof(local));
            if(status<0)
            {
                  printf("Kunne ikke binde socket: %s\n",strerror(errno));
            }
            status=listen(sd,5); // Lyttende Socket
            if(status<0)
            {
                  printf("Kunne ikke lytte til socket: %s\n",strerror(errno));
            }
            sd2=accept(sd,0,0); // Acceptere Connections
            if(sd2<0)
            {
                  printf("Kunne ikke acceptere socket: %s\n",strerror(errno));
            }
  DWORD ThreadId;
  DWORD MainThreadId = GetCurrentThreadId();
  cout << "Start thread" << std::endl;
  CreateThread(0, 0, ThreadFunc, (LPVOID )MainThreadId, 0, &ThreadId);
  }
  system("Pause");
  return 0;
}

På Forhånd mange Tak
Avatar billede quiw Nybegynder
09. januar 2006 - 11:08 #2
- Og hvordan laver jeg globale variabler ?.. Som kan bruges af alle threads? ...
Avatar billede arne_v Ekspert
09. januar 2006 - 12:25 #3
bare erklær dem globale (ovenover både main og tråd funktionen)

men pas på med tilgangen !!
Avatar billede quiw Nybegynder
09. januar 2006 - 13:05 #4
kan du give et kort eksempel?..
- Og eventuelt en løsning på hvorfor mit program skriver sådan..
Avatar billede arne_v Ekspert
09. januar 2006 - 14:05 #5
WSAStartup skal næppe være inde i løkken
Avatar billede arne_v Ekspert
09. januar 2006 - 14:06 #6
sd2 skal vel sendes over i tråden
Avatar billede quiw Nybegynder
10. januar 2006 - 10:33 #7
Mange tak .. Umiddelbart ser min kode nu sådan her ud:

#include <iostream>

using namespace std;

#include <windows.h>

//Globale variabler:
            int sd,sd2,status,len,ix;
            char cmd[100],*p;
            char buf[2000];
            struct sockaddr_in local;
           

DWORD __stdcall ThreadFunc(void *lpParameter)
{
  DWORD MainThread = (DWORD )lpParameter;
  while(1)
  {
            p=(char *)&cmd;
            ix=0;
            char* messages;
            messages="Welcome Online! \n";
            send(sd2, messages, strlen(messages),0);
           
            while((len=recv(sd2,p+ix,1,0))>0) // Modtager tegn i array
            {
                  ix=ix+len;
                  if(cmd[ix-1]=='\n')
                  {
                                // Commands start:
                                cmd[ix-1]='\0';
                               
                                if(cmd[strlen(cmd)-1]=='\r')cmd[strlen(cmd)-1] = '\0';
                                ix=0;
                               
                                messages="<console> ";
                                send(sd2, messages, strlen(messages),0);
                               
                                if ( strcmpi ( cmd,"quit") == 0 )
                                {
                                              messages="Aight, Goodbye ! :) \n";
                                              send(sd2, messages, strlen(messages),0);
                                }
                                else
                                {
                                              messages="Unknown Command \n";
                                              send(sd2, messages, strlen(messages),0);
                                }
                                // Commands end:
                  }
            } 
  }
  PostThreadMessage (MainThread, 1000, 0, 0);
  return 0;
}


int main()
{
            WSADATA WSAData;
            WSAStartup(0x0101,&WSAData); //WSA Startup
            sd=socket(AF_INET,SOCK_STREAM,0); // Skaber Socket
            if(sd<0)
            {
                printf("Kunne ikke skabe socket: %s\n",strerror(errno));
            }
            local.sin_family=AF_INET; //Binder socket
            local.sin_port = htons(8888); // Binder socket til port nummer 1234
            local.sin_addr.s_addr = INADDR_ANY; // Binder socket til local IP
            status=bind(sd,(struct sockaddr *)&local,sizeof(local));
            if(status<0)
            {
                  printf("Kunne ikke binde socket: %s\n",strerror(errno));
            }
            status=listen(sd,5); // Lyttende Socket
            if(status<0)
            {
                  printf("Kunne ikke lytte til socket: %s\n",strerror(errno));
            }
  while(1)
  {
            sd2=accept(sd,0,0); // Acceptere Connections
            if(sd2<0)
            {
                  printf("Kunne ikke acceptere socket: %s\n",strerror(errno));
            }
            DWORD ThreadId;
            DWORD MainThreadId = GetCurrentThreadId();
            cout << "New connection comming." << std::endl;
            CreateThread(0, 0, ThreadFunc, (LPVOID )MainThreadId, 0, &ThreadId);
            cout << "New connection startet." << std::endl;
  }
  closesocket(sd2); // Lukker SD2 Socket
  closesocket(sd); // Lukker SD Socket
  WSACleanup(); //WSA Cleanup
  system("Pause");
  return 0;
}


- Altså .. Der er nu opstået et nyt problem .. Når den ene har connectet kører det fint .. Men hvis så 1 mere prøver at connecte får han kun "Welcome" beskeden .. Også kører begge konsoller uden respons .. Er der en løsning på det?
Avatar billede arne_v Ekspert
10. januar 2006 - 10:52 #8
sd2 skal ikke være global men skal med over til tråden
Avatar billede quiw Nybegynder
10. januar 2006 - 10:58 #9
Nu har jeg umiddelbart flyttet SD2 væk fra global og op til tråden.. Men nu sender den overhovedet ikke respons .. Kun sort vindue .. Dvs. Den får forbindelse men ingen respons ..
Avatar billede arne_v Ekspert
10. januar 2006 - 11:04 #10
sd2 skal være lokal variabel i main og så skal den overføres til tråden
via parameter mekanismen

så enten skal du droppe at overføre main thread id - eller du skal
overføre en struct
Avatar billede quiw Nybegynder
10. januar 2006 - 11:10 #11
Ahh .. Nu er jeg lidt lost .. Kan du give mig et eksempel på hvordan min kode så skal se ud?..
Avatar billede arne_v Ekspert
10. januar 2006 - 12:35 #12
følgende er ikke production quality men ser ud til at virke:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

#include <windows.h>

const char *WELCOME="Welcome\r\n";
const char *QUIT="quit\r\n";
const char *BYEBYE="Bye bye\r\n";
const char *UNKNOWN="Unknown command\r\n";
const char *NEWLINE="\r\n";

DWORD __stdcall client(void *p)
{
    int sd2=*((int*)p);
    send(sd2,WELCOME,strlen(WELCOME),0);
    char buf[80];
    memset(buf,0x00,sizeof(buf));
    int ix=0;
    int len;
    while((len=recv(sd2,buf+ix,sizeof(buf)-ix,0))>0)
    {
        ix=ix+len;
        if(strstr(buf,NEWLINE)!=NULL)
        {
            char cmd[80];
            memset(cmd,0x00,sizeof(cmd));
            int cmdlen = (strstr(buf,NEWLINE)-buf)+strlen(NEWLINE);
            memmove(cmd,buf,cmdlen);
            memmove(buf,buf+cmdlen,ix-cmdlen);
            ix=ix-cmdlen;
            memset(buf+ix,0x00,sizeof(buf)-ix);
            if(strcmpi(cmd,QUIT)==0)
            {
                send(sd2,BYEBYE,strlen(BYEBYE),0);
                closesocket(sd2);
                cout << "Client disconnected" << endl;
                break;
            }
            else
            {
                send(sd2,UNKNOWN,strlen(UNKNOWN),0);
            }
        }
    }
    return 0;
}

const int MAXCLI=10;

int main()
{
    WSADATA WSAData;
    WSAStartup(0x0101,&WSAData);
    int sd=socket(AF_INET,SOCK_STREAM,0);
    if(sd<0)
    {
        cout << "Could not create socket: " << strerror(errno) << endl;
    }
    int status;
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port = htons(1234);
    local.sin_addr.s_addr = INADDR_ANY;
    status=bind(sd,(struct sockaddr *)&local,sizeof(local));
    if(status<0)
    {
        cout << "Could not bind socket: " << strerror(errno) << endl;
    }
    status=listen(sd,5);
    if(status<0)
    {
        cout << "Could not listen to socket: " << strerror(errno) << endl;
    }
    int sd2[MAXCLI];
    int n=0;
    while(1)
    {
        sd2[n]=accept(sd,0,0);
        if(sd2[n]<0)
        {
            cout << "Could not accept socket: " << strerror(errno) << endl;
        }
        cout << "Client connected" << endl;
        DWORD id;
        CreateThread(0, 0, client, (LPVOID)&sd2[n], 0, &id);
        n=(n+1)%MAXCLI;
    }
    closesocket(sd);
    WSACleanup();
    return 0;
}
Avatar billede quiw Nybegynder
10. januar 2006 - 13:22 #13
Det virker umiddelbart problemfrit :)
- Vil prøve at arbejde lidt med min egen kode og din kode til jeg forstår det ..
- Smid lige et svar :)
Avatar billede arne_v Ekspert
10. januar 2006 - 13:36 #14
svar
Avatar billede quiw Nybegynder
10. januar 2006 - 18:09 #15
Sådan :)
Avatar billede quiw Nybegynder
10. januar 2006 - 19:44 #16
Nu vi forresten lige er på emnet ..
- Virker winsock så kun på Lan? .. Det ser ikke ud til man kan connecte over internettet ..
Avatar billede arne_v Ekspert
10. januar 2006 - 19:49 #17
du kan sagtens connecte over internet

men måske blokerer firewall for de brugte porte ??
Avatar billede quiw Nybegynder
10. januar 2006 - 19:58 #18
Hm, umiddelbart kunne det godt se sådan ud .. Selv om jeg har tilladt dem .. Men det er vel intet med c++ koden .. Så det spørgsmål hører nok ikke til her inde :)
- Men hvis jeg vil lave en thread mere .. Kan jeg så ikke skrive:
DWORD __stdcall newthread(void *p)
i stedet for "DWORD __stdcall client(void *p)" ?
Avatar billede arne_v Ekspert
10. januar 2006 - 20:43 #19
du kan lave alle de tråd funktioner du vil
Avatar billede quiw Nybegynder
10. januar 2006 - 21:34 #20
Umiddelbart ser det ikke ud til den starter tråden .. Over tråden "client" lavede jeg en tråd funktion som hed "DWORD __stdcall msgsend(void *p)"
Og da jeg ville kører tråden skrev jeg:
DWORD id;
        CreateThread(0, 0, client, (LPVOID)&sd2[n], 0, &id);
- Men den ville ikke compillere.. Så ændrede det til:
DWORD it;
        CreateThread(0, 0, client, (LPVOID)&sd2[n], 0, &it);
- Altså med "IT" i stedet for "ID" .. Så kunne den godt compillere, men tråden startede ikke ..
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester



IT-JOB