The future, at least for the next years, is based in networks and standards. Even big companies that always tried to hide all its internal file formats, have changed partially its mind, and now it seems they have discovered the fire, talking about XML, SOAP, RPC, and things like this, that probably, could be usual stuff today if they were put some effort and money on them in the past.
No one can imagine isolated devices today : you have to extract data from them, know what's happening even if you are in the other side of the world. Devices are made by different manufacturers, and costumers think it's not their matter to make them compatible. So, companies need standars to share information. Companies need to control its money, information is power and a chance to grow and earn new money. Companies trust in the support of big hardware and software companies.
Here's where we find XML-RPC and SOAP. They are protocols to allow computers to talk between them. Using this protocol, they can do more than sharing some documents: one computer can send orders to other computer to perform some task, and then the second computer will return the result of the action. You can find this into your computer : some programs call to libraries and other programs to perform its work. The only new thing in XML-RPC and SOAP, is that now, conversations are not only into your computer, but between computers. But this is a big thing. The idea is not new at all, but now, it is based on network and data format standards: To carry the information HTTP, to write orders, questions and answers, XML. The end of this is that today, it is quite easy for programmers and even for some users, to write programs that will be connected with other programs running in other computers, in different parts of the world. And the other important point, is that, you don't need to have a defined hardware-software platform, they are standards : you can both buy hardware and software from many different providers. You can buy what you need : low price? high performance? scalability?, just look, compare, and buy or even use freely the best thing for you.
Gambas needs to implement standars, and I'd say more : Linux needs Gambas. Gambas is a BASIC language interpreter. BASIC is an easy language, anybody can learn a little, and start making little programs and scripts. A lot of programmers started learning BASIC when they were children, may be on 8-bits CPUs. A lot of people working in different sections of different companies, knows at least a little of BASIC language. They are not programmers at all, but they have what they need as they can write macros to help them on his work with little and medium data bases, spread-sheets and text documents. They know how to create a formulary, write and read data from tables, share some information sending it by mail... By other side, there are tons of web depelopers, too busy to learn about pointers and memory management, they have to write HTML, create beautiful pictures, administrate servers, deal with hackers and many other things. They need a simple language to create CGI's. There are things like PHP or Perl, but there's one called ASP which is not more than BASIC mixed with HTML, so they know BASIC.
So, the conclusion is that lots of people are waiting for BASIC to migrate to Linux. What can we do here? We are in the middle of the road : we have a simple and well-designed GUI (not very much projects can say that), we have the interpreter, and we have lots of libraries written in C or C++ waiting to help us, may be the biggest API that any operating system has ever known. To cross to the other side we need only to implement that standars that will allow programmers and users to connect to the information they need. Network component is a piece in that target: Let's open the door that will give us the rest of the world.
It is not really a component, it will be implemented in (at least) three components: gb.net, gb.net.curl and gb.xml.
Currently the web is based on TCP/IP protocols. We can say that the IP part of this protocol is matter of operating system, we have to care about TCP part. To implement all stuff we have the following classes:
'libcurl' is a free and portable library written by some people at http://curl.haxx.se. It provides all the pieces needed to manage high level network protocols, like HTTP, FTP and TELNET. This library will be useful to write a component with the following classes:
Note that gb.xml is not yet fully implemented.
A socket is just a place from where you can read and write data. However, socket definition does not speak about servers, clients, connections, etc, this is a concept placed in the next floor. TCP and Local sockets are particular socket implementations in which there are flow control and specifications about the program roles: client and server.
There are two ways to work with connected sockets:
To create a program in which you will connect to a remote or local server using TCP sockets or Local sockets, you have to use "Socket" class. We will use here two ways to implement that, the first implementation does not use any event:
' Gambas module file PUBLIC MySock AS Socket ...
Now, the first thing we do is initialize the object:
... PUBLIC SUB Main() MySock=NEW Socket ...
Then, we have to connect with remote or local server, so we need to use Connect() method. If we want to connect using TCP protocol, we need to specify remote host name or ip, and port to connect to:
... MySock.Connect ( "name_of_host",3450 ) ...
If we need to connect to a Local server (UNIX sockets), we have to specify path from that socket:
... MySock.Connect ("/path/to/socket") ...
The connection process takes a time, so we can not start sending or receiving data in the next line of code, instead, we have to wait until connection is finished or there's an error trying to connect. If we really connect, "Status" property from Socket will change to value Socket.Connected (value 7), but if connection process fails, Status property will change to a value less than zero. So, we'll wait in a loop...
... DO WHILE (MySock.Status <> 7) And (MySock.Status >0 ) WAIT 0.1 LOOP ...
Note that you must use "Wait" method, to let the event loop update Socket Status. After that, let's indicate an error code, something failed, or, if connection was stablished, let's send some data:
... IF MySock.Status <> 7 THEN PRINT "Error" QUIT END IF WRITE #MySock, "hello",5 ...
Now, let's read reply from server. First, we wait until there's data to read, checking it with Lof method. Then, we will read data:
... DO WHILE Lof(MySock)=0 WAIT 0.1 LOOP READ #MySock, sBuf, Lof(MySock) PRINT sBuf ...
Finally, we close the socket:
... CLOSE #MySock
That's all.
The full code is:
PUBLIC MySock AS Socket PUBLIC SUB Main() DIM sBuf AS String MySock = NEW Socket MySock.Connect("name_of_host", 3450) DO WHILE (MySock.Status <> 7) AND (MySock.Status > 0) WAIT 0.1 LOOP IF MySock.Status<>7 THEN PRINT "Error" QUIT END IF WRITE #MySock, "hello",5 DO WHILE Lof(MySock)=0 WAIT 0.1 LOOP READ #MySock, sBuf, Lof(MySock) PRINT sBuf CLOSE #MySock END
Now, let's implement another version, by using events and not active waiting.
' Gambas class file STATIC App AS ClsMain PUBLIC MySock AS Socket ...
At _New method from our class, we'll start socket connection:
... PUBLIC SUB _New() MySock=NEW Socket AS "MySock" MySock.Connect("name_of_host",3450) END ...
At main method, we create a new instance of our class, so we start connection, as _New method is called when creating an object :
... STATIC PUBLIC SUB Main() App=NEW ClsMain END ...
When connection has been stablished successfully, "Ready" event from socket raises, and we send our string to server :
... PUBLIC SUB MySock_Ready() WRITE #MySock,"Hello",5 END ...
But, if there was an error, the Error event raises :
... PUBLIC SUB MySock_Error() PRINT "Unable to connect" END ...
When new data arrives, the Read event raises, so we read that data, put it on screen, and close the socket :
... PUBLIC SUB MySock_Read() DIM sCad AS String READ #MySock,sCad,Lof(MySock) PRINT sCad CLOSE #MySock END ....
Here is the full code:
' Gambas class file STATIC App AS ClsMain PUBLIC MySock AS Socket PUBLIC SUB MySock_Ready() WRITE #MySock,"Hello",5 END PUBLIC SUB MySock_Read() DIM sCad AS String READ #MySock,sCad,Lof(MySock) PRINT sCad CLOSE #MySock END PUBLIC SUB _New() MySock=NEW Socket AS "MySock" MySock.Connect("name_of_host",3450) END PUBLIC SUB MySock_Error() PRINT "Unable to connect" END STATIC PUBLIC SUB Main() App=NEW ClsMain END
To work a a server, we need 'ServerSocket' class. It listen for connections, and returns a new Socket object for each client connection, so we can manage multiple clients.
STATIC Server AS ClsServer PUBLIC Clients AS Object[] PUBLIC Srv AS ServerSocket ...
At program start, we create the instance of our class.
... STATIC PUBLIC SUB Main() Server=NEW ClsServer END ...
When class is loaded by the interpreter, it calls to _New method. We initialize here the array of objects, and start the server. To do that, we have to specify TCP port to listen to, type of socket, and call to 'Listen' method
... PUBLIC SUB _New() Clients =NEW Object[] Srv=NEW ServerSocket AS "Srv" Srv.Port=3450 Srv.Type=ServerSocket.Internet Srv.Listen() END ...
If we'd like to use Local or Unix sockets, instead of TCP sockets, we should specify Local socket type, and a path instead of a port
... PUBLIC SUB _New() Clients =NEW Object[] Srv=NEW ServerSocket AS "Srv" Srv.Path="/path/to/my/socket" Srv.Type=ServerSocket.Local Srv.Listen() END ...
When server is listening, each time a client tries to connect to our service, 'Connection' event from server raises. Here we must accept that connection by calling 'Accept' method. It returns to us a 'Socket' object to manage that connection, so there will be a 'Socket' object for each client connection, that we store in our object array
... PUBLIC SUB Srv_Connection(Host AS String) DIM MySock AS Socket PRINT "Accepting connection from --> " & Host MySock=Srv.Accept() Clients.Add(MySock) END ...
Our client will send us 'hello' message, and then 'Read' event from 'Socket' will raise. Note that we use here 'LAST' keyword to know which of our clients has sent that message. Here we read that string, and send our string 'bye'
... PUBLIC SUB Socket_Read() DIM sCad AS String READ #LAST,sCad,Lof(LAST) PRINT "Received data -->" & sCad WRITE #LAST,"bye",3 END ...
Finally, after client has closed the conection, we receive 'Closed' event, and clear that 'Socket' object from our array, as that connection is alive no more
... PUBLIC SUB Socket_Closed() PRINT "Connection closed" Clients.Remove(Clients.Find(LAST)) END ...
The full code is:
' Gambas class file STATIC Server AS ClsServer PUBLIC Clients AS Object[] PUBLIC Srv AS ServerSocket PUBLIC SUB Socket_Read() DIM sCad AS String READ #LAST,sCad,Lof(LAST) PRINT "Received data -->" & sCad WRITE #LAST,"bye",3 END PUBLIC SUB Socket_Closed() PRINT "Connection closed" Clients.Remove(Clients.Find(LAST)) END PUBLIC SUB Srv_Connection(Host AS String) DIM MySock AS Socket PRINT "Accepting connection from --> " & Host MySock=Srv.Accept() Clients.Add(MySock) END PUBLIC SUB _New() Clients =NEW Object[] Srv=NEW ServerSocket AS "Srv" Srv.Port=3450 Srv.Type=ServerSocket.Internet Srv.Listen() END STATIC PUBLIC SUB Main() Server=NEW ClsServer END