Connecting from a Java or C/C++ Client to PB Chat Server

Just starting out? Need help? Post your questions and find answers here.
fastbit66
New User
New User
Posts: 9
Joined: Tue Jan 17, 2012 2:05 pm

Connecting from a Java or C/C++ Client to PB Chat Server

Post by fastbit66 »

Hello dear PB Coders!

I have a question and I hope someone can help me out with some information:

I have coded a chat server in PureBasic (what else :-).

Is it possible to connect to this server with a Java or C/C++ Client?

I mean i Have a simple TCP/IP client that can send a string to a server.

What is necessary to send to the PB Server so that it recognizes a client that wishes to connect?

Is this possible at all?

It would be great if I can write a simple client on may Android phone with JAVA to talk
over my PB Server.

Here you can see the code for e really simple c client that can connect to a server.
It is built just with a sample I found in a C/C++ programming book:
But if I point it to my PB Server nothing happens on the server.
The C client works an can connect to an appropriate C server.

Thanx in advance for your time!!!
Andi

Code: Select all

/* client.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifdef _WIN32
/* Headerfiles für Windows */
#include <winsock.h>
#include <io.h>

#else
/* Headerfiles für UNIX/Linux */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif

#define PORT 1234
#define RCVBUFSIZE 8192

/* Funktion gibt aufgetretenen Fehler aus und
 * beendet die Anwendung. */
static void error_exit(char *errorMessage) {

#ifdef _WIN32
    fprintf(stderr,"%s: %d\n", errorMessage, WSAGetLastError());
#else
    fprintf(stderr, "%s: %s\n", errorMessage, strerror(errno));
#endif
    exit(EXIT_FAILURE);
}

int main( int argc, char *argv[]) {
    struct sockaddr_in server;
    struct hostent *host_info;
    unsigned long addr;

#ifdef _WIN32
    SOCKET sock;
#else
    int sock;
#endif

    char *echo_string;
    int echo_len;

#ifdef _WIN32
    /* Initialisiere TCP für Windows ("winsock"). */
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD (1, 1);
    if (WSAStartup (wVersionRequested, &wsaData) != 0)
        error_exit( "Fehler beim Initialisieren von Winsock");
    else
        printf("Winsock initialisiert\n");
#endif

 /* Sind die erforderlichen Kommandozeilenargumente vorhanden? */
    if (argc < 3)
        error_exit("usage: client server-ip echo_word\n");

    /* Erzeuge das Socket. */
    sock = socket( AF_INET, SOCK_STREAM, 0 );


    if (sock < 0)
        error_exit( "Fehler beim Anlegen eines Sockets");

    /* Erzeuge die Socketadresse des Servers.
     * Sie besteht aus Typ, IP-Adresse und Portnummer. */
    memset( &server, 0, sizeof (server));
    if ((addr = inet_addr( argv[1])) != INADDR_NONE) {
        /* argv[1] ist eine numerische IP-Adresse. */
        memcpy( (char *)&server.sin_addr, &addr, sizeof(addr));
    }
    else {
        /* Für den Fall der Fälle: Wandle den
         * Servernamen bspw. "localhost" in eine IP-Adresse um. */
        host_info = gethostbyname(argv[1]);
        if (NULL == host_info)
            error_exit("Unbekannter Server");
        /* Server-IP-Adresse */
        memcpy( (char *)&server.sin_addr,
                host_info->h_addr, host_info->h_length );
    }
    /* IPv4-Verbindung */
    server.sin_family = AF_INET;
    /* Portnummer */
    server.sin_port = htons( PORT );

    /* Baue die Verbindung zum Server auf. */
    if(connect(sock,(struct sockaddr*)&server,sizeof(server)) <0)
        error_exit("Kann keine Verbindung zum "
                   "Server herstellen");

    /* Zweites Argument wird als "echo" beim Server verwendet. */
    echo_string = argv[2];
    /* Länge der Eingabe */
    echo_len = strlen(echo_string);

    /* den String inkl. Nullterminator an den Server senden */
    if (send(sock, echo_string, echo_len, 0) != echo_len)
        error_exit("send() hat eine andere Anzahl"
                   " von Bytes versendet als erwartet !!!!");


    /* Schließe Verbindung und Socket. */
#ifdef _WIN32
    closesocket(sock);
    /* Cleanup Winsock */
    WSACleanup();
#else
   close(sock);
#endif

    return EXIT_SUCCESS;
}

DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Connecting from a Java or C/C++ Client to PB Chat Server

Post by DarkDragon »

Yes it is possible. I have done it a few times. Show us the code of your PB server.
bye,
Daniel
fastbit66
New User
New User
Posts: 9
Joined: Tue Jan 17, 2012 2:05 pm

Re: Connecting from a Java or C/C++ Client to PB Chat Server

Post by fastbit66 »

Hi !

Here's the code of the server.
I know it'S ugly code - but works fine so far ;-)

It opens a console an shows the users connected to the server.
It simply sends a received message to all connected clients.
In addition the chat session is saved in a file.
The PING handle is to hold the connection from clients to the server.
I found that if I send nothing from a client to the server the connection gets lost after some time.
So a client sends simply a PING every 30 seconds to hold the connection.
The server does nothing with it.

Thank you !
Andi

Code: Select all

; simple chat server



Port = 443 ; https Port

nick.s  ; to hold a single user
nicks.s ; to hold the string with all users

Global NewList ClientID.l()        ; List to hold the ClientID's of all clients connected to the server
Global NewList Nicks.s ()


If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf




If CreateNetworkServer(0, Port)
  
  
  
   OpenConsole()
   
   PrintN("SOURA CHAT Server - Server created on Port "+Str(Port)+Chr(10)+Chr(13))
  
  Repeat
    Delay(5) ; interrupts the program for 5 ms - so the the rest of the system gets cpu time - 
             ; if theres no delay the program eats 99 % of system time ;-)
    
    SEvent = NetworkServerEvent() 
    
    If SEvent
     
    
     Select SEvent
        
      Case #PB_NetworkEvent_Connect: ; a new client has connected to the server
        
        
        If CountList(ClientID()) = 0
        
        Date$ = FormatDate("%yyyy.%mm.%dd", Date())

        Time$ = FormatDate("%hh.%ii.%ss", Date())


         Sys_time.s = Date$+"_"+Time$+".log"  
        
        OpenFile(0,Sys_time) ; create a file for the chat log - creates it if not exists otherwise opens it
        
        EndIf          
        
        
        AddElement(ClientID())                  ; save the clients ID in the list - EventClient() detects the ID
                  ClientID() = EventClient()
        
        
        
      
      Case #PB_NetworkEvent_Data:   ; server has received raw data from a client
          
          Buffer = AllocateMemory(1000) ; allocate 1000 Bytes in memory as buffer              
                            
          ReceiveNetworkData(EventClient(), Buffer, 1000); read the full 1000 Bytes of the allocated buffer from client
          
          ;---Ping handle
          If FindString(PeekS(Buffer),"__PING__",1)
            ;PrintN("Ping received")
            FreeMemory(Buffer)
          
          
          
          ;------LogIn Handle
          
          ElseIf FindString(PeekS(Buffer),"__LOGON__",1)        ; if its a LOGON Request
             
            nick = StringField(PeekS(Buffer),1,",")   ; extract the nickname from the stream
             
            
            AddElement(Nicks())                         ; and store it in the list
                       Nicks() = nick
            
                       
                      ForEach Nicks()
                        nicks+Nicks()+","           ; add a SPACE as separator to each nickname
                      Next
                      
                       
                      nicks+"__NEWUSERLIST__"
                      
                      usercount =  CountList(Nicks())
                      
                                           
                      PrintN(Str(usercount)+" users in list")
                      PrintN(nicks)
                     
               
                    ForEach ClientID() ; send the buffer with the nicks to all connected clients
                      
                      SendNetworkString(ClientID(),nicks)
                    Next
                    
                     nicks = ""  ; clean the nicks string for the next run - it will be rebuild from the list
                     
                    FreeMemory(Buffer)
                    
        
                 
                ;- ---------LogOut Handle 
                    
                     ElseIf  FindString(PeekS(Buffer),"__LOGOUT__",1)        ; if its a LOGOUT Request
                             
                           nick = StringField(PeekS(Buffer),1,",")
                      
                           ForEach Nicks()
                            If Nicks() = nick
                              DeleteElement(Nicks())
                            EndIf
                          Next 
                          
                          ForEach Nicks()
                            nicks+Nicks()+","           ; add a SPACE as separator to each nickname
                          Next
                          
                          
                          nicks+"__NEWUSERLIST__"
                          
                          usercount =  CountList(Nicks())
                          
                          OpenConsole()
                          
                          PrintN(Str(usercount)+" users in list")
                          PrintN(nicks)
                          
                          
                          ForEach ClientID() ; send the buffer with the nicks to all connected clients
                            
                            SendNetworkString(ClientID(),nicks)
                          Next
                          
                          nicks = ""  ; clean the nicks string for the next run - it will be rebuild from the list
                          
                          FreeMemory(Buffer)
                    
                          
                  
                          
                  ;----Chat Data Handle
                  
                   Else
                             ForEach ClientID() ; send the buffer to all connected clients
                               SendNetworkData(ClientID(),Buffer,1000)
                             Next
                            
                            
                            
                              data_string.s = PeekS(Buffer,1000) ; get out a string from the data buffer
                              
                              FileSeek(0, Lof(0))           ; set the filepointer to the end of the file cause we want to append in the file      
                              
                              WriteStringN(0, data_string)   ; write the chat data buffer   
                              FlushFileBuffers(0)           ; flush the file buffer -> write immediately to file 
                            
                            FreeMemory(Buffer) ; clear the buffer so theres no rubbish left over from previous message ;-) 
          
            EndIf                
         
        
                  
          Case #PB_NetworkEvent_Disconnect:
                            
                             ; delete the clients id from the dynamic list of connected clients
                            ; this is important in case the client reconnect with the same ID
                            ; in that case we would have rubbish from the preveous session
                            ; so we delete it and add it on a new reconnect                                                                
            
            
                              
                              ForEach ClientID()
                                  If ClientID() = EventClient()
                                  DeleteElement(ClientID())
                                 EndIf
                              Next
                              
                             
                                
                             
          EndSelect
   EndIf
    
    
    If CountList(ClientID()) = 0
    CloseFile(0)
    EndIf
    
        
    
  Until Quit = 1 
  
  
  CloseNetworkServer(0)
  CloseFile(0)   
Else
  MessageRequester("Error", "Can't create the server (port in use ?).", 0)
EndIf



End   
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Connecting from a Java or C/C++ Client to PB Chat Server

Post by DarkDragon »

You're using port 1234 in you C code and port 443 in your purebasic code.
bye,
Daniel
fastbit66
New User
New User
Posts: 9
Joined: Tue Jan 17, 2012 2:05 pm

Re: Connecting from a Java or C/C++ Client to PB Chat Server

Post by fastbit66 »

Hi Daniel!

Oh sorry - yes that was a fault I made.

I copied and pasted this code from the ebook I use for C Programming - cause I didn't had my own code here when I posted it.

In my code at home I use port 443 in pb proggy and in the c program as well.
fastbit66
New User
New User
Posts: 9
Joined: Tue Jan 17, 2012 2:05 pm

Re: Connecting from a Java or C/C++ Client to PB Chat Server

Post by fastbit66 »

Do you need more information ?

Any help would be appriciated !

Thx a lot !

Andi
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Connecting from a Java or C/C++ Client to PB Chat Server

Post by DarkDragon »

As you're using an old PureBasic version (you still use CountList) you probably won't have IsFile. Well and your loop is blocked by the debugger when it gets here:

Code: Select all

    If CountList(ClientID()) = 0
      CloseFile(0)
    EndIf
CountList(ClientID()) will always return 0 at the beginning and your file is not open at this moment. So you are closing a file which hasn't been opened. You need to remember the state of the file. E.g. with a variable, which you declare and define at the beginning:

Code: Select all

Define FileOpened.i = 0
Then you simply set it to the result of OpenFile when calling it:

Code: Select all

FileOpened = OpenFile(0, Sys_time)
And you check at the end of the loop if FileOpened is not equal to 0:

Code: Select all

    If CountList(ClientID()) = 0 And FileOpened <> 0
      CloseFile(0)
      FileOpened = 0
    EndIf
So the full code looks like this:

Code: Select all

; simple chat server



Port = 1234 ; https Port

nick.s  ; to hold a single user
nicks.s ; to hold the string with all users

Global NewList ClientID.l()        ; List to hold the ClientID's of all clients connected to the server
Global NewList Nicks.s ()


If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf

Define FileOpened.i = 0




If CreateNetworkServer(0, Port)
  
  OpenConsole()
  
  PrintN("SOURA CHAT Server - Server created on Port "+Str(Port)+Chr(10)+Chr(13))
  
  Repeat
    Delay(5) ; interrupts the program for 5 ms - so the the rest of the system gets cpu time - 
    ; if theres no delay the program eats 99 % of system time ;-)
    
    SEvent = NetworkServerEvent() 
    
    If SEvent
      
      
      Select SEvent
          
        Case #PB_NetworkEvent_Connect: ; a new client has connected to the server
          
          
          If CountList(ClientID()) = 0
            
            Date$ = FormatDate("%yyyy.%mm.%dd", Date())
            
            Time$ = FormatDate("%hh.%ii.%ss", Date())
            
            
            Sys_time.s = Date$+"_"+Time$+".log"  
            
            FileOpened = OpenFile(0, Sys_time) ; create a file for the chat log - creates it if not exists otherwise opens it
            
          EndIf          
          
          
          AddElement(ClientID())                  ; save the clients ID in the list - EventClient() detects the ID
          ClientID() = EventClient()
          
          
          
          
        Case #PB_NetworkEvent_Data:   ; server has received raw data from a client
          
          Buffer = AllocateMemory(1000) ; allocate 1000 Bytes in memory as buffer              
          
          ReceiveNetworkData(EventClient(), Buffer, 1000); read the full 1000 Bytes of the allocated buffer from client
          
          ;---Ping handle
          If FindString(PeekS(Buffer),"__PING__",1)
            ;PrintN("Ping received")
            FreeMemory(Buffer)
            
            
            
            ;------LogIn Handle
            
          ElseIf FindString(PeekS(Buffer),"__LOGON__",1)        ; if its a LOGON Request
            
            nick = StringField(PeekS(Buffer),1,",")   ; extract the nickname from the stream
            
            
            AddElement(Nicks())                         ; and store it in the list
            Nicks() = nick
            
            
            ForEach Nicks()
              nicks+Nicks()+","           ; add a SPACE as separator to each nickname
            Next
            
            
            nicks+"__NEWUSERLIST__"
            
            usercount =  CountList(Nicks())
            
            
            PrintN(Str(usercount)+" users in list")
            PrintN(nicks)
            
            
            ForEach ClientID() ; send the buffer with the nicks to all connected clients
              
              SendNetworkString(ClientID(),nicks)
            Next
            
            nicks = ""  ; clean the nicks string for the next run - it will be rebuild from the list
            
            FreeMemory(Buffer)
            
            
            
            ;- ---------LogOut Handle 
            
          ElseIf  FindString(PeekS(Buffer),"__LOGOUT__",1)        ; if its a LOGOUT Request
            
            nick = StringField(PeekS(Buffer),1,",")
            
            ForEach Nicks()
              If Nicks() = nick
                DeleteElement(Nicks())
              EndIf
            Next 
            
            ForEach Nicks()
              nicks+Nicks()+","           ; add a SPACE as separator to each nickname
            Next
            
            
            nicks+"__NEWUSERLIST__"
            
            usercount =  CountList(Nicks())
            
            OpenConsole()
            
            PrintN(Str(usercount)+" users in list")
            PrintN(nicks)
            
            
            ForEach ClientID() ; send the buffer with the nicks to all connected clients
              
              SendNetworkString(ClientID(),nicks)
            Next
            
            nicks = ""  ; clean the nicks string for the next run - it will be rebuild from the list
            
            FreeMemory(Buffer)
            
            
            
            
            ;----Chat Data Handle
            
          Else
            ForEach ClientID() ; send the buffer to all connected clients
              SendNetworkData(ClientID(),Buffer,1000)
            Next
            
            
            
            data_string.s = PeekS(Buffer,1000) ; get out a string from the data buffer
            
            FileSeek(0, Lof(0))           ; set the filepointer to the end of the file cause we want to append in the file      
            
            WriteStringN(0, data_string)   ; write the chat data buffer   
            FlushFileBuffers(0)           ; flush the file buffer -> write immediately to file 
            
            FreeMemory(Buffer) ; clear the buffer so theres no rubbish left over from previous message ;-) 
            
          EndIf                
          
          
          
        Case #PB_NetworkEvent_Disconnect:
          
          ; delete the clients id from the dynamic list of connected clients
          ; this is important in case the client reconnect with the same ID
          ; in that case we would have rubbish from the preveous session
          ; so we delete it and add it on a new reconnect                                                                
          
          
          
          ForEach ClientID()
            If ClientID() = EventClient()
              DeleteElement(ClientID())
            EndIf
          Next
          
          
          
          
      EndSelect
    EndIf
    
    If CountList(ClientID()) = 0 And FileOpened <> 0
      CloseFile(0)
      FileOpened = 0
    EndIf
  Until Quit = 1 
  
  
  CloseNetworkServer(0)
  CloseFile(0)
Else
  MessageRequester("Error", "Can't create the server (port in use ?).", 0)
EndIf

End
Btw. as your comments are German, why don't you ask in the German forums?
http://www.purebasic.fr/german/
bye,
Daniel
fastbit66
New User
New User
Posts: 9
Joined: Tue Jan 17, 2012 2:05 pm

Re: Connecting from a Java or C/C++ Client to PB Chat Server

Post by fastbit66 »

Hi Daniel !

Thanx a lot for your workaround !

It works now !!!

GREAT !!!!
sNoOOPy
New User
New User
Posts: 4
Joined: Thu Jun 23, 2011 1:13 pm

Re: Connecting from a Java or C/C++ Client to PB Chat Server

Post by sNoOOPy »

"fastbit66:
I found that if I send nothing from a client to the server the connection gets lost after some time."
You can use UDP instead of TCP. A UDP datagram is just an IP+Port+Message by itself with nothing extra. There is no connection to lose because there isn't one to begin with. The client connection is just an ip+port number.

Result = CreateNetworkServer(#Server, Port , #PB_Network_UDP)

UDP is one way only, so you need two ports, one for each direction, but Purebasic handles this automatically and I don't know what it does.

You could make a dll functions in c to handle network traffic and call it from Purebasic.
Post Reply