EXAMPLES ON NETWORKING
======================
Networking is a very wide field. When we think about network programming for personal
use, we think about very exciting projects.
Accessing the internet to get the latest stock prices and automatically update your files
and calculate the total value of your investment, all as one program is one exciting
project.
Accessing your personal web site using the FTP protocol to download files, update them
then upload them back automatically without manual operations is also an exciting project.
Writing a program which checks your e-mail, file saves the useful items and deletes the
rest is also nice to do. Writing a program which sends e-mail to your friends automatically
when some event takes place can also be a great project.
So, let us see how we can do some of these exciting programming projects.
=========================================================================================
EXAMPLE 1: We'll write a program which we can run at any time to get the latest stock
price of Microsoft from CNN's Financial website.
=========================================================================================
// ----------------------- FIRST STEP: Getting the html file ---------------------------
To get the HTML file, you need to know the URL of the page which tells us the stock price. So
access CNN's Financial website and get the stock price manually. The URL you need is the one
displayed at the address line of your browser which is
"http://money.cnn.com/quote/quote.html?symb=MSFT";
==========================================================================================
public class a:pcs {
public override void init() {
tia=toa="t"; // Select "text screen" display
base.init(); // Initialize PC# class
}
public override void run() {
urs="http://money.cnn.com/quote/quote.html?symb=MSFT";
jb=true;kb=true;nm("hg");tm(); //Get html file replacing {}<> with |'s
}
}
=========================================================================================
TUTORIAL: The address at CNN's financial web site for quotes is only:
"http://money.cnn.com/quote/quote.html"
The rest of the URL is the query string. It starts with '?' followed with a number of
"parameter=value" strings seperated with '&' char's. We can't tell for sure what CNN means
by their parameters, but we can guess that "symb=MSFT" means Symbol=Microsoft's stock symbol.
Calling the Networking method nm() at mode "hg" gets the html file. The html file is huge
in size, so we must think of eliminating some of its unnecessary text in order to reach
where Microsoft's stock price is fast.
We know that HTML is full of tags enclosed in brackets like these < > which we have no need
for. Also there are plenty of script data between braces { } which we don't need. We can
eliminate both types if we supply the method with (jb=true;kb=true;) Instead of just removing
them, the method replaces each pair of them and the data in between with one '|' since this
may help us when we search for the necessary data.
After this elimination, the file we get may have lost 2/3 of its size, so we can at least
look through it to know where the wanted data is. Here is what we see:
=========================================================================================

// ------------------------- SECOND STEP: Searching the text ---------------------------
The "PC# Reference, Desktop" discusses how to search a string in details. Each search job
requires a unique strategy. The wanted data is the "63.24" Look at the text around it:
Microsoft Corp |(NASDAQ:MSFT)|||||Add to Watch List||||Set Alert|||||||||63.24||
Delayed Data|As of
The word "MSFT" which is in upper cased letters and surrounded with a ':' and a ')' is unique
in the file, so we can use it for the search. We can get the string which starts immediately
after ":MSFT)" and ends immediately before the phrase "As of" by calling the search
method as follows:
js=":MSFT)";ks="As of";tm("s");
The resulting string comes assigned to (os), so:
os="|||||Add to Watch List||||Set Alert|||||||||63.24||Delayed Data|".
How can we extract the stock price from this string? Notice the following:
(1) If we scan the string backward, the first digit we meet is the last char of the wanted
data.
(2) The wanted data is made of numbers, one decimal point and may contain commas. The char
which immediately precedes wanted data could not be any of those characters.
Using those two features we can extract the stock price. Here is the complete program to get
the data, search it and display the stock price:
==========================================================================================
public class a:pcs {
public override void init() {
j=1000;k=550;dm("s");
tia=toa="t"; // Select "text screen" display
base.init(); // Initialize PC# class
}
public override void run() {
//------ Get the page ------
urs="http://money.cnn.com/quote/quote.html?symb=MSFT";
jb=true;kb=true;nm("hg");//tm(); //Get html file replacing {}<> with |'s
//------ Pick data around the price ------
txs=os; // Assign file to search string (txs)
js=":MSFT)";ks="As of";tm("s"); // Get the string between js & ks and assign it to (os)
//------ Remove chars following the price ------
for(c=os.Length-1;c>-1;c--) { // Scan (os) char's backward. Stop at first numeric char
if("0123456789".IndexOf(os.Substring(c,1))>-1) break;
}
os=os.Substring(0,c+1); // Remove all chars after that one from (os)
//------ Remove chars preceding the price ------
for(c=os.Length-1;c>-1;c--) { // Scan (os) char's again. Stop at first char which
if("0123456789.,".IndexOf(os.Substring(c,1))<0) break;
} // is not a digit, decimal point or comma.
os=os.Substring(c+1); // Remove all char's upto that one from (os)
os="Latest stock price for Microsoft: $"+os;tm();
} // Now (os) contains nothing but the price. Display it.
}
====================================================================================

=========================================================================================
ACCESSING FTP SITES
===================
How good are our FTP access methods?
====================================
Our FTP access methods are faster and more reliable than many of the commercial FTP access
softwares available. This is one reason for you to write your own software to upload your
files and directories to your FTP site by yourself.
The major advantage in writing your own FTP software is the elimination of manual operations
which are subject to human errors. Your ftp site address, your username, your password and
the pathnames of all the files to be uploaded can be stated into your software instead of
being asked for by the software each time you run it. This should make your upload operation
always accurate and error free.
Let us have an example.
=========================================================================================
EXAMPLE 2: In this example, you will access your web site using FTP protocol and do the
following in order:
(1) Create new direcory named "dir1".
(2) Upload the local file "test.txt" from your working directory to the new directory at
your website. Before you start, you need to create the "test.txt" file at your working
directory and write some text into it using Notepad.
(3) Download the same file from the server back to your working directory using the new
name "test1.txt" for the received file.
(4) Delete the file "test.txt" at your website.
(5) Delete the directory "dir1" at your website.
So at the end your website will be restored to original condition and your working
directory will contain the two files "test.txt" and "test1.txt" containing the same data.
=========================================================================================
We'll display a dialog box before the execution of each operation to give you the choice
to either perform it or skip it. This will also allow you the time to access your website
manually to cofirm that the previous operation has been executed properly.
You need to modify some lines, replacing "Your user ID", "Your Password" and "Your server"
with your actual data. The lines which need modifications are marked with "***".
=========================================================================================
public class a : pcs { // Always remember, class name = file name
public override void init() {
tia=toa="t"; // Use Text Screen for text display
base.init(); // Should be last statement in init()
}
public override void run() {
ids="your user ID";pss="Your Password";// *** You need to modify this line so it
// contains your actual user ID & Password.
// --------------------------------- CREATING DIRECTORY ---------------------------------
cls="r0";os="CREATING NEW DIRECTORY:";tm();
// Display in red on Text Screen
cls="S9";os="Create new directory (dr1)?";ks="yn";cm("d");
// Display choice dialog with "yes/no" buttons
if(os.IndexOf("y")>-1) { // If user clicked on "Yes"
urs="ftp://your host.com/dir1";nm("fmd");// *** You need to modify this line so it
// contains the actual name of your host
tm(); // Display the FTP status returned.
}
// ----------------------------------- UPLOADING A FILE ----------------------------------
cls="r0";os="\nUPLOADING A FILE:";tm();
cls="S9";os="Click OK to upload file (test.txt)";ks="yn";cm("d");
if(os.IndexOf("y")>-1) {
fls="test.txt";
urs="ftp://your server.com/dir1/test.txt";// *** Modify
nm("fpf");
tm();
}
// ---------------------------------- DOWNLOADING A FILE ----------------------------------
cls="r0";os="\nDOWNLOADING A FILE:";tm();
cls="S9";os="Click OK to download file (test.txt)";ks="yn";cm("d");
if(os.IndexOf("y")>-1) {
urs="ftp://your server.com/dir1/test.txt";// *** Modify
fls="test1.txt";
nm("fgf");
tm();
}
// ---------------------------------- DELETING THE FILE -----------------------------------
cls="r0";os="\nDELETING THE FILE:";tm();
cls="S9";os="Click OK to delete the file (test.txt)";ks="yn";cm("d");
if(os.IndexOf("y")>-1) {
urs="ftp://your server.com/dir1/test.txt";// *** Modify
nm("fdf");
tm();
}
// ------------------------------- DELETING THE DIRECTORY ---------------------------------
cls="r0";os="\nDELETING DIRECTORY:";tm();
cls="S9";os="Click OK to delete new directory (dr1)";ks="yn";cm("d");
if(os.IndexOf("y")>-1) {
urs="ftp://your server.com/dir1"; // *** Modify
nm("fdd");
tm();
}
}
}
=========================================================================================
TUTORIAL:
---------
The ftp address always starts with "ftp://" since this part represents the
protocol. Additionally, some ftp host names also start with "ftp" like
"ftp://ftp.microsoft.com.
Authentication is a must for ftp servers. The ones which accept anonymous caller expect
you to use the word "anonymous" as your user ID and your e-mail address as your password.
There is nothing else to explain in this section, we hope you have had no problem with
this example.
Giving your FTP program administrator privilege:
------------------------------------------------
If you are using Windows 10, your FTP program may not be allowed to save files unless it
has the administrator privilege. So, you need to do to your ".exe" file what you have done
to Notepad to correct the same problem. Read "Reference-Desktop" under the title "GETTING
THE MESSAGE 'ACCESS IS DENIED' WHEN ATTEMPTING TO SAVE A FILE".
=========================================================================================

=========================================================================================
SENDING AND RECEIVING E-MAIL
============================
=========================================================================================
EXAMPLE 3: We are going to send an e-mail with an attachment file programatically.
If your outgoing mail server requires authentication, you need to supply your User ID and
Password assigned to (ids,pss) respectively. If it does not, supply (ids=pss="";)
You need to supply the e-mail address of both sender and recipient. If you decide to send
the message to yourself, use your e-mail address for both.
We are going to be using "pix.jpg" as the attachment file. Make sure it is available at
your working directory. It will be considered your personal picture which you send as a
gift to your friend.
The lines which require your modifications are marked with "***".
=========================================================================================
public class a:pcs {
public override void init() {
tia=toa="t";
base.init();
}
public override void run() {
gm("dn"); // Stop display to avoid flickering while
// message is sent
uhs="Your SMTP Server Name.com"; // *** Replace with your SMTP server address.
ids="Your User ID";pss="Your Password";// *** Replace with actual ID, Password.
js="YourID@YourHost.com"; // *** Sender E-Mail address
ks="HerID@HerHost.com"; // *** Recipient E-Mail address
os="My gift to you."; // Message Subject
OS[0]="Dear Friend"; // Message Body made of 2 lines.
OS[1]="My picture to you with love!";
fls="pix.jpg"; // File to be attached
ib=true;nm("ms"); // Send the message with attachment
gm("dn"); // Restore display
os="Message Sent.";tm(); // Inform user
}
}
=========================================================================================
Sending e-mail messages in full color:
--------------------------------------
The body of the message you send does not have to be in "plain text", it can contain HTML.
This allows you to send messages in different colors and fonts and to include pictures
within them.
When you get to the "Demonstrative Examples - Web Applications", you'll learn how to
modify example 3 so that the body's two lines show in different colors and the picture
becomes part of the message body.
=========================================================================================

EXAMPLE 4: This example will show you how to obtain a list of all new messages which your
incoming mail server has received for you, how to retrieve any message on the list and
how to delete a message.
Before we get to the example, you need to know what the "Outlook Express" or similar mail
utilities do when they receive your mail. They obtain the list of new messages from the
server, retrieve a copy of each message, store it locally then instruct the server to
delete the message there. They do this operation each specific number of minutes while
the computer is on depending on your settings.
The messages which you see when you check the inbox of the "Outlook Express" have already
been deleted at the server. So don't expect to find them when you run your program to
check for new messages. Your program can only find the few messages which have been
received at the server and the "Outlook Express" has not received them yet.
So, you may like to temporarely disable the Outlook Express's automatic message retrieval
feature in order to give your program a chance to find enough new messages. To do so, run
the "Outlook Express", click on [Tools] then [Options]. At the "General" page of the
"Options" window, uncheck the Checkbox labled "Check for new messages every.." then click
on [Apply], [OK].
You may also send yourself some messages to add to the list of messages which your program
is going to find.
The lines which require your modifications are marked with "***".
=========================================================================================
public class a:pcs {
public override void init() {
tia=toa="t";
bli=0;
base.init();
}
public override void run() {
if (blp==0) { // Obtaining the list
cls="r0";os="GETTING NEW MESSAGES LIST:";tm();
uhs="Your POP Server Name.com";ids="Your User ID";pss="Your Password";// ***
// *** Replace with your actual data.
nm("mc");cls="S9";tm(); // Get new msg's list and display
cls="b0";os="Enter the number of the message which you like to retrieve.";
bli=1;tm("i");return; // Get info from user then goto blk 1
}
if (blp==1) { // Retrieving a message
om("ti");n=o; // Convert msg no. to int, assign to (n)
cls="r0";os="RETRIEVING A MESSAGE:";tm();
i=n;nm("mr"); // Retrieve message
cls="S9";tm(); // Display message
cls="b0";os="Enter the number of the message which you like to delete.";
bli=2;tm("i");return; // Get info from user then goto blk 2
}
if (blp==2) { // Deleting a message
om("ti");n=o; // Convert msg no. to int, assign to (n)
cls="r0";os="DELETING A MESSAGE:";tm();
i=n;nm("md"); // Delete message
cls="S9";tm(); // Display server cofirmation msg.
cls="b0";os="Enter 'r' to repeat program or 'e' to exit.";
bli=3;tm("i");return; // Get info from user then goto blk 3
}
if (blp==3) { // Executing what to do next
om("l"); // Convert user's choice to lower case
if (os.Equals("e")) sm("e"); // Exit prog if "e" was selected
else bli=0;um("b");return; // Jump to block 0 if "r" was selected.
}
}
}
=========================================================================================
TUTORIAL: The new message list which you see on display shows the message number followed
with a number indicating the message size. The message number which starts by "1" is the
number to use to tell the server which message you like to retrieve or delete.
The messages which you receive from the mail server contain very large amount of
information which you don't need. So you need to search the data and obtain the data which
you need.
=========================================================================================

===============================================================================================
Resolving IP-Addresses:
=======================
We all know that an IP-Address can be expressed in a numeric format like "207.46.232.182"
and in a friendly string format like "microsoft.com".
Method nm() at mode "r" can resolve an IP Address from the string format to the numeric one
and vice versa. It expects the address to be resolved to be assigned to (urs) and it also
sends the result assigned to (urs)
One problem is that a server could have one string address which resolves to more than one
numeric address. For this reason, when you resolve string format to numeric one, the method
returns two items, OS[] containing all results and (urs) containing the first numeric address
in OS[]
EXAMPLES:
---------
(1) urs="google.com";nm("r");os=urs;tm(); displays: 72.14.207.99
(2) urs="google.com";nm("r");os=OS[0];tm(); displays: 72.14.207.99
(3) urs="google.com";nm("r");os=OS[1];tm(); displays: 64.233.187.99
(4) urs="google.com";nm("r");os=OS[2];tm(); displays: 64.233.167.99
(5) urs="72.14.207.99";nm("r");os=urs;tm(); displays: eh-in-f99.google.com
(6) urs="64.233.187.99";nm("r");os=urs;tm(); displays: jc-in-f99.google.com
(7) urs="64.233.167.99";nm("r");os=urs;tm(); displays: py-in-f99.google.com
Notice that if you use your browser to retrieve the web pages whose addresses are displayed
in (5):(7), you'll always get the same "www.google.com" page.
If you are wondering where the DNS (Domain Naming Service) database which we are accessing came
from, it came with the ".NET framework" software which you have downloaded from Microsoft.
===============================================================================================
DEVELOPING SERVERS
==================
For version 1.6 or higher
We know it has been fun to communicate with the mail server, except that we have had only half
of the fun. The people who developed the server had the other half. Can we write our own server
software to have it all? Yes we can.
DEVELOPING A TCP SERVER:
========================
We are going to start with the TCP server. The TCP server works at the transport layer and
this means that it is protocol dependant. If both server and client send data at the same time,
communication will break down. So a protocol must be set and both server and client must abide
with it.
The server communication software is also as crtical as the protocol. It requires extra care.
For this reason we are taking a different approach with the server than we have taken with the
client. The TCP server runs in one piece. You start it using nm("tss") At the mean time you
prepare a method which tells the server how to answer the messages received and instructs it to
disconnect a call or to stop whenever necessary.
For the more advanced, the three main objects which the server operates on are made public, so
you can also work on them if you find it necessary. The three objects are:
tsp: Present TcpListener object;
tcp: Present TcpClient object.
nsp: Present NetworkStream object.
If all I have is one personal computer, can I use it to test server-client communication?
-----------------------------------------------------------------------------------------
Yes. You can have both server and client software on the same computer. The host name you will
be connecting to in this case is "localhost". You'll see how to do this in the following
examples.
Starting the server:
--------------------
You start the server by calling nm("tss") supplying it with the following parameters:
urs: Local IP Address to listen to. A server can have more than one IP Address if it has more
than one network card. The address supplied must be in dotted numeric form like
(urs="196.50.25.1") You can resolve an address in a string format to numeric format by
calling nm("r") If you keep (urs="") Server will listen to all IP Addresses available.
upi: Port number to listen at. If you like to select one which is guaranteed not to interfer
with anybody else's, select one in the range (50,000:60,000)
i : Number of the method which you have prepared that contains all the necessary logic. For
example if you have used method m5(int t), make the assignment (i=5) These methods have
been discussed in the chapter of "Handling Threads".
k : Receive Timeout. Should be set unless you accept default. Timeout is important since this
server runs synchronously, It cannot serve next call unless current call has been
terminated.
Deciding upon a Protocol:
-------------------------
You are the one who writes the code which analyzes client messages, so make sure the protocol
allows you to get what client wants easily and error free. Make it simple for the client too.
Your code must correct as many client errors as possible and must inform him/her of the error
if correction was not possible.
It will be nice if you allow clients to ask for help by sending the message "Help", "?" or
"Commands" which can get them instruction for what to do.
Making the logic method:
------------------------
As explained above, you should use one of the 10 methods "m0() to m9()" which have been made
originally for threads. The methods expect a thread number which is unnecessary for this
application, but it must be there. So if you have decided to use method m5(), your code should
look like this:
public override void m5(int t) {
.........
}
and the server will be calling m5(0)
The server will be calling your method each time its status changes and each time it receives
a message. It will supply your method with two items:
1. (os) containing the data regardless if it was a message or a new status code.
2. (ib) The status flag. When you find that (ib) is set, you know that the data in (os) is a
status code. If reset, the data is a received message.
The status codes can be "l", "c", "s" or "e" meaning "Listening", "Connected", "Stopped" or
"Ended with an error".
===============================================================================================
EXAMPLE 6: Write two classes, a TCP client class named "tc" which will be similar to the
one of Example 5 and a TCP server class named "ts" which will start the PC# internal TCP
sever. The second class should contain a logic method as explained above.
The server will be called "Math server" it will be serving answers to trigonometric
functions questions. The client will be sending commands like "Function:cos,Operand:45"
to expect the answer for (cos 45). The protocol also includes sending one's name to the
server with "Name:AnyName". The command "Bye" will be used for logging off.
===============================================================================================
THE SERVER CLASS:
-----------------
public class ts:pcs {
//------------------------------------ Starting the Server -----------------------------------
public override void run() {
cm("fe"); // Eliminate form.
cls="r0";dm("ccf"); // Change Console color to red
os="To Stop Server Press [Control][Break]";tm();
cls="S9";dm("ccf"); // Display message. Restore black color.
upi=55000;urs="";i=9;k=1000;nm("tss"); // Stsrt TCP server using port 55000. Listen to all
} // available IP addresses. use m9(int t) for logic
// and set Receive Timout to 1000 ms.
//--------------------- Method m9() (Contains logic to be used by server) --------------------
public override void m9(int t) {
// IN:os=Message received or status code ib=Status flag ib=true:status code in (os),
// ib=false:message received in (os) Status code can be: l/c/s/e meaning Listening/
// Connected/Stopped/Ended with Error.
// OUT:For status change calls os="" must be returned except for code "c", you may assign
// a message in (os) to inform client that a connection has been established.
// For message received calls, you assign to (os) a reply message to be sent to client.
// Returning (ob=true) instructs server to disconnect client.
// Returning (dnb=true) instructs server to stop.
// PROTOCOL: (1) Server informs client when connection has been successfully made.
// (2) Client may send his/her ID's with [Name:his/her_name] and expect reply.
// (3) Client may send trigonometric function question as [Function:fn,Operand:op]
// where fn=Any trigonometric function name and op=Angle in degrees (0:360)
// and expect one message reply.
// (4) Client can close connection by sending [Bye] and expect no reply.
// (5) When client sends invalid command, server sends back one informing message.
// REMARK: (n) will be used to count connections.
try {
string fn="",op="";bool er=false; // Define var's for function, operand & errors
string o1s=os; // Store (os) temporarely
//---------------------------------- Status change calls --------------------------------
if (ib) { // If this was a status change call:
if (o1s=="c") { // If status=Connected:
n++; // Increment connection counter.
os="Server Connected... Calls received so far: "+n;tm();
// Display a message on local console.
os="Math Server Ready."; // Return this message to be sent to client.
}
else if (o1s=="l") { // If status=Listening:
os="Ready for calls.... Calls received so far: "+n;tm();
// Display a message on local console.
os=""; // You must return nothing into (os)
}
else if (o1s=="s") { // If status=Stopped:
os="Server Stopped..... Calls received so far: "+n;tm();
// Display a message on local console.
os=""; // You must return nothing into (os)
}
else if (o1s=="e") { // If status=Ended with error:
os="Error encountered.. Calls received so far: "+n;tm();
// Display a message on local console.
os=""; // You must return nothing into (os)
}
return; // Return back to server.
}
//--------------------------------- "Message received" calls ------------------------------
//--- Correcting client's errors--- Any "=" will be replaced with the expected ":" and
// any ";" will be replaced eith the expected ",". All spaces will be removed and the
// string will be converted to all lower cased char's before analysing commands.
os=""; // Start with empty (os)
char[] C=o1s.ToCharArray(); // Copy (o1s)'s chars to array rows
for (int i=0;i< o1s.Length;i++) { // Scan (o1s)'s char's
t=(int)C[i]; // t=ASCII code of each char
if (t<33) continue; // Skip spaces and all lower char's
if (C[i]=='=') C[i]=':'; // Change any '=' char with ':'
if (C[i]==';') C[i]=','; // Change any ';' char with ','
os+=C[i]; // Add char to (os)
}
om("l"); // Change all char's to lower case.
o1s=os; // Reassign string to (o1s)
//--- The "Bye" command ---
if (o1s.IndexOf("bye")>-1) { // If message received was "Bye"
ob=true;return; // Send instruction to disconnect client.
}
//--- Analysing first term (left of ",") --- The "Name" command will be done here.
c=o1s.IndexOf(","); // c=position of ","
if (c>-1) { // If "," was available:
fn=o1s.Substring(0,c); // Assign text on its left side to (fn)
op=o1s.Substring(c+1); // and text on its right side to (op)
}
else fn=o1s; // If "," was not available fn=full string
if (fn.Length<1) er=true; // if (fn) was smaller than expected, quote error
else { // Else if length of (fn) was OK:
c=fn.IndexOf(":"); // c=Position of ":" in (fn)
if (c>-1) { // If ":" found:
os=fn.Substring(c+1);ns=os; // os=Text at its right side, save it temporarely
if (fn.IndexOf("name")>-1) { // If was the "Name" command, Make a welcome
os="Welcome to the Math Server "+os;return;
} // message to caller and return it to server
else fn=ns; // Reduce (fn) to text on right side of ":" only
} // which is the name of the function wanted.
else er=true; // Else if no ":" found, quote error.
}
//--- Analysing second term (right of ",") --- The "Math question" will be done here.
if (op.Length<9 || op.IndexOf("operand")<0) er=true;
// If 2nd term was too short or no "Operand" found,
else { // quote error. Else:
c=op.IndexOf(":"); // c=Position of ":" in (op)
if (c>-1) { // If ":" was available:
os=op.Substring(c+1);op=os; // Reduce (op) to text on right side of ":" only
om("td");js=fn;um("mt"); // Convert (os) to double. Call um() to get the
os=fn+" "+op+" = "+od;return; // answer (comes in od). Assign reply to (os)
} // and send it back to the server.
else er=true; // Else if no ":" found, quote error.
}
if (er) { // If any error was found:
os="Invalid command.";return; // Return this reply message to server.
}
}
catch {
os="Error has been detected while processing your command.";
return;
}
}
}
THE CLIENT CLASS:
-----------------
public class tc:pcs {
public override void init() {
tia=toa="t";
base.init();
}
public override void run() {
cls="r0";fns="trb14";tm("c"); // Set font,color, clear screen.
os=" COMMUNICATING WITH OUR MATH SERVER\n";tm();
fns="trb12"; // Display title, Change font
cls="b0";os="CLIENT: Connecting ...";tm(); // Announce next action
uhs="localhost";upi=55000;nm("to"); // Open connection with local server listening
// at port 55000
nm("tr"); // Read server response
cls="S9";os="SERVER: "+os;tm(); // Display server response
cls="b0";os="CLIENT: Name: John";tm(); // Announce next action
os="Name: John";nm("tw"); // Send "Name" command
nm("tr"); // Read server response
cls="S9";os="SERVER: "+os;tm(); // Display server response
cls="b0";os="CLIENT: Function:sin, Operand:30";tm();
// Announce next action
os="Function:sin, Operand:30\n";nm("tw"); // Send "math inquiry" Command
nm("tr"); // Read server response
cls="S9";os="SERVER: "+os;tm(); // Display server response
cls="b0";os="CLIENT: Function:tan, Operand:45";tm();
// Announce next action
os="Function:tan, Operand:45\n";nm("tw"); // Send another "math inquiry" Command
nm("tr"); // Read server response
cls="S9";os="SERVER: "+os;tm(); // Display server response
cls="b0";os="CLIENT: Bye";tm(); // Announce next action
os="Bye\n";nm("tw"); // Send "Bye" command
nm("tc"); // Close connection
}
}
===============================================================================================
Save the server class into file "ts.cs" and the client class into file "tc.cs". Compile the
two classes with: pcp ts and pcp tc
To run the two classes on the same computer, open two Command Mode windows. one for the server
and one for the client. Both should point to your working directory if the ".exe" files of
both the server and client were there.
Start the server first by: ts [ENTER] then move to the second window and start the client
by: tc [ENTER].
RESULTS: This is what you see on server's console:
C:\pcs>ts
To Stop Server Press [Control][Break]
Ready for calls.... Calls received so far: 0
Server Connected... Calls received so far: 1
Ready for calls.... Calls received so far: 1
Server Connected... Calls received so far: 2
Ready for calls.... Calls received so far: 2
Server Connected... Calls received so far: 3
Ready for calls.... Calls received so far: 3
And this is what you see at the client:

===============================================================================================
DEVELOPING A MULTI-THREAD TCP SERVER:
=====================================
The single-thread server which we have worked with in example 6 is fast and reliable. It allowed
you to include your logic method into your server class which extends (pcs) This has made things
easy for you. All necessary objects have been accessable to you which was also an advantage.
However, one major problem with the single-thread server is that it can help one client at a
time. If one client did his job slowly, all the clients who come after him suffer. We can cut
the slow callers off by setting the timeout at a low value, but this will not be the solution
which makes everyone happy.
So, the solution is multi-thread server which helps more than one client simultaneously, so the
slow client cannot affect the rest.
We have developed a multi-thread server which is reliable, can handle any protocol and runs at
great speed. Interfacing with it is not the same as with the single-thread server. Let us see
how to start it first.
The Personal C Sharp Utilities class (pcsut):
---------------------------------------------
Initially, the servers have been included into class (pcs) Now, class (pcs) is signed and a
signed class is not allowed to reference an unsigned one. The servers need to reference your
Logic classes, so to solve this problem we have moved the server to the utilities class which is
unsigned.
The utilities class (pcsut) extends class (pcs) Your server class extends (pcsut), this allows
it to access all (pcs) methods. Any class which references class (pcsut) or any inner class which
it contains must include this commented statement above the class declaration statement:
//assembly pcsut.exe;
The PC# tools which you compile your class with, reads this commented statement and learns that
class (pcsut) can be found into file "pcsut.exe" which is located into current directory.
Make sure to leave no space between the "//" and the letter "a".
Starting the server:
--------------------
You start the server by calling nm("tsm") supplying it with the following parameters:
REMARK: The only necessary par's are (urs,upi), there are defaults for all others.
urs: Local IP Address to listen to. A server can have more than one IP Address if it has more
than one network card. The address supplied must be in dotted numeric form like
(urs="196.50.25.1") You can resolve an address in a string format to numeric format by
calling nm("r") If you keep (urs="") Server will listen to all IP Addresses available.
upi: Port number to listen at. If you like to select one which is guaranteed not to interfer
with anybody else's, select one in the range (50,000:60,000)
k : Receive Timeout. Should be set unless you accept default.
jf,kf: Min number of Worker Threads and completion Port Threads respectively. Default (1,1)
lf,of: Max number of Worker Threads and completion Port Threads respectively. Default (25,1000)
Making the logic method:
------------------------
In order to allow the server to run at the maximum possible speed, we had to change the way
you supply your logic method to the server. The logic method is not included into the server
class; instead it's part of another class named "TLogic". Class "TLogic" implements an interface
with the name "ITLogic" which is included internally into class (pcsut) So, the interface's name
is "pcsut.ITLogic". TLogic handles logic for TCP servers. Later you'll learn about class HLogic
which is a similar class that handles logic for HTTP servers.
The logic method name is "ServerLogic". It expects three parameters, a string, an integer and
an object. The string supplies the data which can be a message received from the client or a
status code.
The integer is the "Connection counter". The counter, this time is incremented by the server
in a thread safe manner and supplied to your logic method as a parameter.
The object is of class "RxTx" which is included into class (pcsut) internally. It handles the
reception and transmission of data for the TCP servers. This object is necessary only for the
advanced programmers who like to do additional operations which are not included into PC#
software. We are going to get into that later. This object will be neglected in the next
example.
Method "ServerLogic" returns a string value. This value can be a reply to be sent to client
or an instruction to the server to disconnect current client or to stop.
When the string sent by the server to the logic method is a status code, it should contain two
char's, a '*' symbol followed with the status code. So it should be as follows:
*l meaning "Listening".
*c meaning "Connected".
*s meaning "Stopped".
*e meaning "Ended with error".
When the string returned by the logic method to the server is an instruction code, it should
also contain two char's, a '#' symbol followed with the instruction code. So it should be as
follows:
#d meaning "Disconnect current client".
#s meaning "Stop".
#n meaning "No reply to be sent".
REMARK: You can return "#n" only if you have sent the reply to client by yourself. Will see
how to do that in a coming example.
Writing the logic code:
-----------------------
When you have been writing the logic method for a single-thread server, it was done in a class
which extends (pcs), and you have had no worry about threads, so you have been using PC# methods.
Now, PC# methods are unavailable. You should write in C# directly. Each thread will be receiving
an instance of the "Logic" class which contains your method.
Class "TLogic" is compiled to a "dll" file using tool "pcl". Both the "cs" and the "dll" files
must be available in your working directory all the time since class (pcsut) expects them to be
there. Do not delete them. If you lose them accidentally run (pcs) again to recreate all PC#
tools as you did when you started with PC#. The files will be created with the minimum required
code which is as follows:
public class TLogic:pcsut.ITLogic {
public string ServerLogic (string os,int counter,pcsut.RxTx rt) {
return os;
}
}
You can also create the "TLogic.cs" and "TLogic.dll" by calling nm("lc")
Finally, the multi-thread server will be running so fast that the messages which you display
on the server's console will not be able to follow. This could make the messages meaningless.
So make them as few and as short as possible.
Since this class is implementing an interface which is inside class (pcsut) it must include
this commented statement above its class declaration statement as explained before:
//assembly pcut.exe;
About the next example:
-----------------------
This time, we are concerned mainly about server speed. So, we are going to simplify the protocol,
reduce the displayed messages and eliminate the TextScreen.
Each client will send three commands:
(1) After connecting to the server, the client Will pick a random number, send it to the server
as is; then display the result received (which is the square of the number) on the console.
(2) The second command will be a repitition of (1) using another random number.
(3) The third command will be the "Bye" command to logoff then closes connection.
The client will then repeat the same procedures 100 times.
===============================================================================================
EXAMPLE 7: Redo example 6 using the multi-thread server instead of the single thread one. This
requires modified versions of classes (ts) and (tc) in addition to the new class (TLogic)
The client will be connecting, sending a random number to the server twice and displaying the
server's reply on console, then it will send the "Bye" command to logoff. The procedure will be
repeated 100 times in order to check server's speed.
===============================================================================================
THE SERVER CLASS:
-----------------
//assembly pcsut.exe;
public class ts:pcsut { // Server class extends (pcs)
public override void run() {
cm("fe"); // Eliminate form.
cls="r0";dm("ccf"); // Change Console color to red
os="To Stop Server Press [Control][Break]";tm();
cls="S9";dm("ccf"); // Display message. Restore black color.
upi=55000;urs="";nm("tsm"); // Start TCP server using port 55000. Listen to all
} // available addresses.
}
THE CLIENT CLASS:
-----------------
public class tc:pcs { // Client class extends (pcs)
public override void run() {
for (n=0;n<100;n++) { // Repeat contacting server 100 times
cm("fe"); // Eliminate form
uhs="localhost";upi=55000;nm("to"); // Open connection with localhost at port 55000
i=9;um("mr"); // Get a random number in the range 0:9
os=""+o;nm("tw"); // Send the number to server
nm("tr"); // Get server's reply
os="Receiving: "+os;tm(); // Display it.
// i=300;um("s"); // 300 ms delay (See below)
i=9;um("mr"); // Get another random number in the range 0:9
os=""+o;nm("tw"); // Send the number to server
nm("tr"); // Get server's reply
os="Receiving: "+os;tm(); // Display it.
os="Bye";nm("tw"); // Logoff.
nm("tc"); // Close connection.
} // Repeat.
}
}
THE LOGIC CLASS:
----------------
//assembly pcsut.exe;
public class TLogic:pcsut.ITLogic { // Logic class implements interface pcs.ITLogic
//----------------- Method ServerLogic (Contains logic to be used by server) ----------------
public string ServerLogic (string os,int counter,pcsut.RxTx rt) {
// IN:os=Message received or status code If call was for status change, (os) will contain:
// "*l", "*c", "*s" or "*e" meaning Listening, Connected, Stopped or Ended with Error.
// counter: Connection counter updated by server.
// Object of class RxTx.
// OUT:os=Message to be sent or instruction code. If instructions, (os) will contain:
// "#d", "#s" or "#n" meaning "disconnect caller", "stop" or "Send no reply".
// PROTOCOL: (1) Server does not inform client when connection has been made.
// (2) Client may send any number alone and expect to receive the square of that
// number.
// (3) Client can close connection by sending [Bye] and expects no reply.
if (os.Length<1) return os; // If received empty string return it as is
string o1s=os; // Keep a copy of original (os)
//----------------------------------- Status change calls ---------------------------------
if (os.Length==2 && os.Substring(0,1)=="*") {
os=os.Substring(1,1); // If this was a status change call get status code
if (os=="c") { // If status=Connected:
Console.WriteLine("Connections: "+counter);
// Display a message on local console.
os=""; // You must return nothing into (os)
}
else if (os=="l" || os=="s" || os=="e") {
os=""; // Return nothing for all other 3 status codes.
}
return os; // Return back to server.
}
//-------------------------------- "Message received" calls -------------------------------
os=os.ToLower(); // Convert string to l/c
//--- The "Bye" command ---
if (os.IndexOf("bye")>-1) { // If message received was "Bye"
os="#d";return os; // Send instruction to disconnect client.
}
// Else we expect (os) to contain a number.
os=""+Math.Pow(Convert.ToDouble(os),2); // Get the square of the number into (os)
os=o1s+"^2 = "+os;
return os; // Return back to server.
}
}
===============================================================================================
Save the server class into file "ts.cs" and the client class into file "tc.cs". Compile the
two classes with: pcp ts and pcp tc
Save the Logic class into file "TLogic.cs". Compile it to a library file (.dll) with:
pcl TLogic
To run the two classes on the same computer, open two Command Mode windows. one for the server
and one for the client. Both should point to your working directory if the ".exe" files of
both the server and client were there.
Start the server first by: ts [ENTER] then move to the second window and start the client
by: tc [ENTER].
Demonstrating the advantage in using multi-thread server:
---------------------------------------------------------
If every thing worked fine, go back to the client class. Uncomment the line:
// i=300;um("s"); // 300 ms delay (See below)
Change the class name to "tc1" and save it into a new file named "tc1.cs". Compile the file
with: pcp tc1
Now you have one server file and two client ones. Client (tc1) runs slower than client (tc)
Open a third Command Mode window, run the server (ts) in the first window as you have done
before. Run the slow client (tc1) into the second window and immediately go to the third
window and run the faster client (tc)
Notice that the fast class runs fast and the slow class runs slow. This means that they don't
affect each other as they could have done if single thread server was used.
Configuring the multi-thread server to run on single thread:
------------------------------------------------------------
To complete this demo, we are going to set the server for one thread operation. To do that,
we set the maximum threads to be used to 1. so modify the server code as follows:
Add the statement (lf=of=1;) to the line of class (ts) which makes the call nm("tsm")
Here is how it should be:
lf=of=1;upi=55000;urs="";nm("tsm"); // Start TCP server using port 55000. Listen to all
// available addresses.
Now compile the (ts) file again and repeat what you did before and notice that the two clients
have become equally slow.

===============================================================================================
DEVELOPING A MULTI-THREAD HTTP SERVER:
======================================
It is now the time for the HTTP sever. HTTP servers serve files only. They use a restrict
protocol which is the HTTP. They communicate with web browsers which know the HTTP protocol very
well, so they don't expect the same problems which general TCP servers expect.
The problem with HTTP server design is that the HTTP protocol requirements are many. Servers are
required to supply the browsers with plenty of information. However, browsers normally use
defaults for any missing information and also try to figure out the missing items by their own.
At present time, our HTTP server which you'll be accessing in the next example, supplies three
items to the browser when it receives a request:
(1) The status which tells the browser why it could not fill the request when it could not.
(2) The content type of the requested file, so the browser knows how to execute the file.
(3) The length of the file in bytes, so the browser can tell if it has downloaded the file
properly.
The HTTP server we have developed requires operating systems not earlier than Windows XP SP2 or
Windows Server 2003. It will not work with earlier versions. It's still simple, however it's a
multi-thread server which is reliable and runs fast.
The status code:
----------------
There are many of them. At present time we only use the following:
" ": Send nothing. File has already been sent.
"ok": OK
"nf": NotFound
"fr": Forbidden
"ua": Unauthorized
"nm": NotModified
"mv": Moved
"rd": Redirect
"br": BadRequest
The Content Type:
-----------------
Content types are too many. We have included only few of them. However, whenever you leave
the content type unassigned, the browser figures it out by inspecting the file extension.
The content types which our HTTP server can send at present time are:
" ": Unknown. Left for the browser to determine
"th": text/html
"tp": text/plain
"tx": text/xml
"tc": text/css
"ax": application/xml
"ig": image/gif
"ip": image/png
"ij": image/jpeg
"vx": video/x-mng
The complete IP address:
------------------------
The default port number for HTTP is (80) The complete IP address of a website should include
the port number at which the HTTP server listens. For example, the complete IP address of
"famsoft.org" is:
http://www.famsoft.org:80
Since port 80 is the default, we don't care to include it when we request web pages. We are
going to be using port 55000 for the next example, so make sure to include the port number
when you test your software.
Prefix URL's:
-------------
The new versions of windows allow more than one program to be accessing the same port at the
same time using HTTP. In order to prevent interference, each program should request serving
files from one or more specific folders or to serve requests coming to one or more specific ports.
No other program should request serving any of those folders or ports. The requested folders
and ports are called Prefixes.
When you start the server, you'll supply method nm("hsm") with the array URS[] loaded with
all the URL prefixes which your program will like to serve.
If the site the server runs on was "famsoft.org" and we like it to serve files from the
subfolder "images" only using port 8080, our prefix should be:
URS[0]="http://www.famsoft.org:8080/images/"
The last "/" is mandatory. The prefix "http://*:8080/" will receive all requests sent to port
8080 and the prefix: "http://localhost/" will serve all requests on the localhost.
Remember to include port numbers in all your prefixes unless you are using port 80.
Now let's talk about your programs.
Starting the server:
--------------------
You start the HTTP server by calling nm("hsm") supplying it with the following parameters:
URS[]: Loaded with all the prefixes which you like to serve. Port number must be included
unless you are using port 80.
jf,kf: Min number of Worker Threads and completion Port Threads respectively. Default (1,1)
lf,of: Max number of Worker Threads and completion Port Threads respectively. Default (25,1000)
Making the logic method:
------------------------
This time, the name of the logic class is "HLogic" and the name of the method which the server
calls is still ServerLogic() Class HLogic emplements the interface IHLogic which is included
into class (pcsut) The method receives a string, an integer and an object and returns
a string.
The string this method receives in its general form can be made of two strings seperated from
each other with a "|". The first string is the URL which is requested by the browser in order
to obtain a copy of the file which the URL represents. The second string is available only if
the call was to submit a form. The second string in this case contains form data which is made
of "key=value" strings seperated from each others with "&".
The integer it receives is the connection counter which the server updates in a thread safe
manner exactly as the TCP server does.
The object is of class "HRxTx" which is included into class (pcsut) internally. It handles the
reception and transmission of data for the HTTP server. This object is necessary only for the
advanced programmers who like to do additional operations which are not included into PC#
software. The public variables which you can access are (assuming that rt is the object's
reference name):
rt.OY The byte array of class RxTx.
rt.hc The HttpListenerContext object reference which the current thread handles.
You can use the HttpListenerContext to do any operation which PC# does not do for you.
Expected return data of method ServerLogic():
---------------------------------------------
The returned string is prepared by you. It should be in the form:
sc|ct|message/file where:
sc : is the 2-char status code which you assign to the operation (see above)
ct : is the 2-char content-type code which you provide based on the file content which
you know.
message/file: If the status code was "ok", you should seperate the file from the URL you received
from the server, modify it if necessary to make it the actual path of the file
and add it to the string returned. If the status code was "mv" or "rd", you should
add the new URL here. If the status code was anything else, you may if you want
add a message to be displayed at the browser (If the browser allows)
The three pieces of information are seperated from each other with vertical bars '|'.
REMARK: Using the HTTP server requires the file "HLogic.dll" to be available into your working
directory. You can use mode "lc" to create the minimum code version of this file.
Recreating Personal C Sharp tools (by running pcs) generates the file also.
The Client class:
-----------------
There is no client class to be made this time. The browser is going to be the client.
===============================================================================================
EXAMPLE 8: Write a server class to start the HTTP server and modify the Logic class to
allow serving only the images available into the "images" subfolder of your working directory.
Test retrieving the images using your browser. Whenever the image "icon.pnp" is requested,
redirect client to "http://www.famsoft.org".
===============================================================================================
THE SERVER CLASS:
-----------------
//assembly pcsut.exe;
public class hs:pcsut {
public override void run() {
cm("fe"); // Eliminate form.
cls="r0";dm("ccf"); // Change Console color to red
os="To Stop Server Press [Control][Break]";tm();
cls="S9";dm("ccf"); // Display message. Restore black color.
// Start TCP server using one prefix which is "serving all files on localhost" when requests
// come to port 55000.
URS[0]="http://localhost:55000/";nm("hsm");
}
}
THE LOGIC CLASS:
----------------
//assembly pcsut.exe;
public class HLogic:pcsut.IHLogic { // Logic class implements interface pcs.IHLogic
//----------------- Method ServerLogic (Contains logic to be used by server) ----------------
public string ServerLogic (string os,int counter,pcsut.HRxTx rt) {
// IN:os=URL received from browser + Post string (if available)
// counter: Connection counter updated by server.
// rt: Instance of class HRxTx which is the calling class.
// OUT:os=String prepared here which contains "Status code", "Content-Type code" and a file
// path, a URL or a message depending on status code.
if (os.Length<1) return "br"; // If received empty string return "BadRequest"
//-------------------------------- "Message received" calls -------------------------------
int i;string ps=""; // Define general use int and a str. for post data
i=os.IndexOf("|");
if (i>-1) {
ps=os.Substring(i+1);
os=os.Substring(0,i);
}
if (os.Substring(os.Length-1,1)=="/") os=os.Substring(0,os.Length-1);
// If URL ends with "/", eliminate it.
// Getting wanted file from URL received. Scan URL backward. Stop when 1st "/" is met.
for (i=os.Length-1;i>-1;i--) if (os.Substring(i,1)=="/") break;
if (i<0) return "br"; // If no "/" found, return status="Bad Request"
os=os.Substring(i+1); // Get string following last "/" (file wanted)
// Check file:
if (os.Length<7) return "nf"; // If shoter than expected, return "Not Found"
os=os.ToLower(); // Convert to lower case
if (os=="icon.pnp") return "rd|th|http://www.famsoft.org";
// If was file "icon.pnp", redirect to another page
else if ("flower.jpg icon.jpg pix.jpg icon.bmp icon.ico ".IndexOf(os)<0) return "nf";
// If not a file we like to serve, return Not Found
// Make Status codes:
string cts=" "; // Start with " " meaning unknown content type
if (os.IndexOf(".jpg")>-1) cts="ij"; // Set content type for jpeg file
// If status="OK", Get full path:
os="ok|"+cts+"|c:\\pcs\\images\\"+os; // Add the rest of the file path.
Console.WriteLine("Connection number: "+counter+" Sending file: "+os.Substring(6));
return os; // Send the complete string after displying it.
}
}
===============================================================================================
REMARKS:
(1) We have assumed that the path for your working directory is "c:\pcs". If it was
something else, modify the line commented with "Add the rest of the file path." accordingly
in class Logic's code.
(2) As you can see, the person who requests the file using his browser does not have to
know the exact file path on your system which is good for security. He requests it as if it
was in the root folder of "http://localhost". You are the one who tells the server what the
full path is.
Compiling and testing the server classes:
-----------------------------------------
Save the server class into file "hs.cs". Compile the class with:
pcp hs
Save the Logic class into file "HLogic.cs". Compile it to a library file (.dll) with:
pcl HLogic
Start the server by: hs [ENTER]
Start the Internet Explorer and type into its address bar:
http://localhost:55000/flower.jpg and push [ENTER]
The flower image should show up. Hit the "Refresh button" to make sure that the image did not
come from the browser's cash. Repeat the procedure to get all other images in the folder.
Now, Try requesting the file "icon.pnp", it should redirect you to our website. Also try
requesting any file which is unavailable in the "images" folder, you should get the
"HTTP 404 Not Found" message.
---------------------------------------------------------------------------------------------
This is what you see on server's console:
C:\pcs>hs
To Stop Server Press [Control][Break]
Connection number: 1 Sending file: c:\pcs\images\pix.jpg
Connection number: 2 Sending file: c:\pcs\images\icon.jpg
Connection number: 3 Sending file: c:\pcs\images\icon.ico
Connection number: 4 Sending file: c:\pcs\images\icon.bmp
Connection number: 5 Sending file: c:\pcs\images\flower.jpg
And this is what you see on the Browser:

===============================================================================================
THE WEB SCREEN:
===============
Using the browser as the HTTP client is reducing our ability to demonstrate more features of the
HTTp server. We must have an HTTP client which operates at a lower level than the one which we
access with nm("hg")
The web client requires a display device which executes and displays HTML in order to see what
it's doing. The TextScreen can only display plain text. It can show the HTML without executing
it which is not enough for this job. This is why we developed the WebScreen.
The WebScreen is of same size as the TextScreen. The major part of it displays HTML. However,
it contains one line text area to display instructions to the user in addition to the usual
text field at the bottom which is available in the TextScreen too. The last two controls respond
to the same commands as their TextScreen counterparts. This means:
os="Enter your name:";tm(); Displays instructions to user.
os="Enter your name:";bli=2;tm("i"); Displays message then receives user's text at block 2.
The WebScreen will accompany our HTTP client through most of the coming examples.
THE HTTP WEB CLIENT:
====================
The HTTP web client is a very capable and easy to use software. The next example will introduce
you to the HTTP web client software and the WebScreen.
===============================================================================================
Example 9: Use the HTTP Client software to retrieve and display Microsoft home page.
===============================================================================================
public class hc:pcs {
public override void init() {
tia=toa="w"; // Text output device=WebScreen
base.init(); // Initialize parent class.
}
public override void run() {
urs="http://www.microsoft.com";nm("ho"); // Open HTTP connection
nm("hw"); // Write request to get the page
nm("hr"); // Read returned data
tm("wd"); // Display received HTML data
nm("hc"); // Close connection
}
}
===============================================================================================

===============================================================================================
The WebScreen can be set into two different modes. The first mode is the "web browser" mode in
which it can get a web page and display it by itself. The second mode is "display only" mode in
which it's capable only of displaying HTML.
Method tm("wd") automatically sets it into the "display only" mode before it loads the HTML
document into it. Method tm("wu") automatically sets it into the "web browser" mode before
it supplies it with the URL of the page to be retrieved and displayed.
HOW TO SUBMIT A FORM PROGRAMMATICALLY:
======================================
Form data is submitted in a similar manner to query data. The only difference is that form data
is sent seperately while query data is attached to the URL. Both are made of "key=value" strings
which are seperated from each others with a "&".
To send the query string, add a '?' to the end of the URL then add the query string to it before
you call nm("ho") When you do so you are using method "GET".
To send POST data, assign it to (os) before you call nm("hwp") When you do so you are using
method POST.
The simplest page example which we have made was example 2 of section "WPDI". So, get into the
home page and run it to familiarize yourself with it before we get into next example.
IN that example we installed a text field and a button. When the user types something into the
text field and clicks the button, we get his text and display it at the bottom preceded with
"You entered: ".
In the next example we want to do this process programmatically. We like to feel the server
that someone has typed "John" into the text field and clicked the button. So we expect to see
the phrase "You entered: John" at the bottom.
Our form is made of two controls, a text field named "tf0" with the value "John" and a button
named "bt0" with the value "Submit" (which is its label) so we expect the post data to be
"tf0=John&bt0=Submit". Is this all it takes? NO.
The ASP.NET uses hidden controls internally. Our form contains a third control named
"__VIEWSTATE" which is a hidden field. That field must be submitted to the server with the rest
of your data or your post data will be neglected.
For this reason, we are going to do the job in two steps. The first step will be getting the
page without sending post data and searching it to get the value of the hidden field. The second
step will be to reopen the page, send post data which include the hidden field, then read and
display the returned page.
===============================================================================================
Example 10: Use the HTTP Client software to interact with Personal C Sharp's web page2 of
WPDI. Send post data to the page which tells the page that the name "John" has been typed into
the page's text field and the page's button has been clicked.
===============================================================================================
public class hc:pcs {
string o1s; // Define a backup string for (os)
public override void init() {
tia=toa="w"; // Text output device=WebScreen
base.init(); // Initialize parent class.
}
public override void run() {
//----------------------------------- First Trip -----------------------------------------
urs="http://www.famsoft.org/WPDI/pg2.aspx";ks="nc";nm("ho");
// Open connection with the page, no cache
nm("hw"); // Write request to get the page
nm("hr"); // Read returned data
txs=os; // Assign data to searchable string
js="__VIEWSTATE";tm("s"); // Remove upto the end of this string
js="value=\"";ks="\"";tm("s"); // Get data between the two strings into (os)
o1s="__VIEWSTATE="+os+"&tf0=John&bt0=Submit"; // Complete the POST string, assign to (o1s)
nm("hc"); // Close connection
//----------------------------------- Second Trip ----------------------------------------
urs="http://www.famsoft.org/WPDI/pg2.aspx";ks="nc";nm("ho");
// Open connection for the second time
os=o1s;nm("hwp"); // Write post data stored into (o1s)
nm("hr"); // Read returned data
tm("wd"); // Display received HTML data
nm("hc"); // Close connection
}
}
===============================================================================================

===============================================================================================
POSTING DATA OF A COMPLEX FORM:
===============================
Let us now look at example 4 of WPDI. The new form contains more controls. It's made of two
sections, one at the left and one at the right, Each section has its own "Submit" button,
Since it's all one form, clicking either one will cause fields of both sections to be
filled up with submitted data. However page4's event handler will only analyze the section
whose "Submit" button is clicked and display read data at the bottom of that section. We are
going to be clicking button "bt1" of the right section.
Let us list the keyname of each control, its label and the data which we like to assign to it.
LEFT SECTION:
-------------
tf0 First Name John
tf1 Last Name Doe
tf2 Street Address 123 Any Street
tf3 City Los Angeles
tf4 State CA
tf5 Zip Code 12345
ch0 Years at this residency Less than Two years
bt0 Submit Not clicked
RIGHT SECTION:
--------------
cb00 Over 65 Unchecked
cb01 Retired Checked
rb00 MasterCard Checked
rb01 Visa Unchecked
tf6 Credit Card number 1111 2222 3333 4444
tf7 Exp Date 01/09
tf8 V Code 123
ta0 Special Instructions Any Instructions
bt1 Submit Clicked
The only controls which we have neglected are the "Label Controls" since they are not submitted.
Here is how each control type is submitted:
TEXT FIELD & TEXT AREA: keyname=The text typed into it.
DROPDOWN LIST: keyname=Text of the selected row.
CHECK BOX : If checked: keyname=on If unchecked: Don't list it.
RADIO BUTTON : If checked: 0=keyname If unchecked: Don't list it.
BUTTON : If clicked: keyname=Button's label If unclicked: Don't list it.
Applying these rules, our post string should be:
"tf0=John&tf1=Doe&tf2=123 Any Street&tf3=Los Angeles&tf4=CA&tf5=12345&ch0=Less than Two years&
cb01=on&0=rb00&tf6=1111 2222 3333 4444&tf7=01/09&tf8=123&ta0=Any Instructions&bt1=Submit"
So, all you need to do is to add the hidden field "__VIEWSTATE" and submit the form.
===============================================================================================
Example 11: Use the HTTP Client software to interact with Personal C Sharp's web page4 and
send post data programmatically.
===============================================================================================
public class hc:pcs {
string o1s; // Define a backup string for (o1s)
public override void init() {
tia=toa="w"; // Text output device=WebScreen
base.init(); // Initialize parent class.
}
public override void run() {
//----------------------------------- First Trip -----------------------------------------
urs="http://www.famsoft.org/WPDI/pg4.aspx";ks="nc";nm("ho");
// Open connection with the page, no cache.
nm("hw"); // Write request to get the page
nm("hr"); // Read returned data
txs=os; // Assign data to searchable string
js="__VIEWSTATE";tm("s"); // Remove upto the end of this string
js="value=\"";ks="\"";tm("s"); // Get data between the two strings into (os)
o1s="__VIEWSTATE="+os; // Complete the POST string, assign to (o1s)
o1s+="&tf0=John&tf1=Doe&tf2=123 Any Street&tf3=Los Angeles&tf4=CA&tf5=12345&";
o1s+="ch0=Less than Two years&cb01=on&0=rb00&tf6=1111 2222 3333 4444&tf7=01/09&";
o1s+="tf8=123&ta0=Any Instructions&bt1=Submit";
nm("hc"); // Close connection
//----------------------------------- Second Trip ----------------------------------------
urs="http://www.famsoft.org/WPDI/pg4.aspx";ks="nc";nm("ho");
// Open connection for the second time
os=o1s;nm("hwp"); // Write post data stored into (o1s)
nm("hr"); // Read returned data
tm("wd"); // Display received HTML data
nm("hc"); // Close connection
}
}
===============================================================================================

===============================================================================================
ENCRYPTING COMMUNICATION BETWEEN SERVER AND CLIENT:
===================================================
In example 4 of the "Security" section, we have discussed how to use symmetric encryption
for the communication between two parties while using asymmetric encryption to encrypt the key
and the initialization vector before sending them over the network. Now we like to try this
method to encrypt the actual communication between a TCP server and a client. There are few
points to be discussed first.
Using Binary data:
------------------
All encryption and decryption methods expect you to supply them with the data either assigned to
(os) if it was text or assigned to OY[] if it was binary. The default is text. To indicate that
you want the binary data in OY[] to be the one to use, you should supply (os="@") or (os="")
The output of the method is always returned in both forms assigned to (os) and OY[].
The data to be encrypted can be text or binary, but the encrypted data which we want to decrypt
is always binary. There is no sense in putting it into text format. However in order to maintain
simplicity, the methods return encrypted data in a base 64 string format. this seems to be useful
when the data is used Within the local system only. If you are going to transport data accross
a network, you can't use the base 64 string. You must use the binary data assigned to OY[].
For this reason, whenever you send encrypted data to the other party, encrypt a binary data or
decrypt encrypted data always make the assignment (os="@") All networking and encryption methods
recognize this symbol as an indication to use data in the byte array OY[] for their operations.
Protocol:
---------
When you are sending text, you can easily label the data you are sending, "Name:John" is an
example. If you are sending binary data, you don't like to add any label (although you can)
For this reason, when we send binary data we do it in two steps. For example when the client
sends the "Key" after encrypting it with the server's public key, it does it as follows:
os="Key:";nm("tw") // Send the string "Key:" meaning that key data is to follow.
The Server answers with "OK". The client then sends the encrypted key data.
As you know, the server does not make the decision on what to send to the client. It only calls
your logic method each time it receives data to get the answer. Your logic method gives the
answer to the server then ends and the control returns back to the server until it receives
new data and calls the logic method again.
When your logic method receives the message "Key:", it needs to memorize that it has received
this message so that when the next trip comes, it will know that it is receiving the key. In the
next example, the character type variable (oc) will be used for this purpose. Here is how it's
done:
if (os.IndexOf("key:")>-1) { // If the message "Key:" is received:
oc='k';os="OK";return; // Mark this event with '(oc='k') Also, tell the server to
} // send "OK" and return.
else if (oc=='k') { // If this is the next call after "Key:" msg was received:
os="@";ks="temp";tm("Ead");JY=OY; // Decrypt key and assign it to JY[] locally.
oc=' ';os="OK";return; // Erase mark. Tell server to send "OK" and return.
}
Here is the full dialogue:
--------------------------
SERVER: PKey:(Server's public key)
CLIENT: Key:
SERVER: OK
CLIENT: (encrypted key binary data)
SERVER: OK
CLIENT: IV:
SERVER: OK
CLIENT: (encrypted IV binary data)
SERVER: OK
CLIENT: This is my secret message!
SERVER: And this is my cofidential reply!
CLIENT: Bye
Now, return back to the "Security" chapter and restudy example 4 before you get further.
===============================================================================================
Example 12: Repeat example 4 of the "Security" chapter making it demonstrate the encryption of
actual communication between a client and server. Use the Single thread TCP server for this
example in order to maintain simplicity.
===============================================================================================
SERVER:
=======
public class ts:pcs {
//------------------------------------ Starting the Server -----------------------------------
public override void run() {
cm("fe"); // Eliminate form.
cls="r0";dm("ccf"); // Change Console color to red
os="To Stop Server Press [Control][Break]";tm();
cls="S9";dm("ccf"); // Display message. Restore black color.
upi=55000;urs="";i=9;k=1000;nm("tss"); // Stsrt TCP server using port 55000. Listen to all
} // available IP addresses. use m9(int t) for logic
// and set Receive Timout to 1000 ms.
//--------------------- Method m9() (Contains logic to be used by server) --------------------
public override void m9(int t) {
// IN:os=Message received or status code ib=Status flag ib=true:status code in (os),
// ib=false:message received in (os) Status code can be: l/c/s/e meaning Listening/
// Connected/Stopped/Ended with Error.
// OUT:For status change calls os="" must be returned except for code "c", you may assign
// a message in (os) to inform client that a connection has been established.
// For message received calls, you assign to (os) a reply message to be sent to client.
// Returning (ob=true) instructs server to disconnect client.
// Returning (dnb=true) instructs server to stop.
// PROTOCOL: See above.
// REMARK: (n) will be used to count connections.
try {
string o1s=os; // Store (os) temporarely
//---------------------------------- Status change calls --------------------------------
if (ib) { // If this was a status change call:
if (o1s=="c") { // If status=Connected:
n++; // Increment connection counter.
os="Server Connected... Calls received so far: "+n;tm();
// Display a message on local console.
ks="temp";tm("Eak"); // Generate asym key-pair, store into container
os="PKey:"+os; // "temp". Send returned public key to client.
}
else if (o1s=="l") { // If status=Listening:
os="Ready for calls.... Calls received so far: "+n;tm();
// Display a message on local console.
os=""; // You must return nothing into (os)
}
else if (o1s=="s") { // If status=Stopped:
os="Server Stopped..... Calls received so far: "+n;tm();
// Display a message on local console.
os=""; // You must return nothing into (os)
}
else if (o1s=="e") { // If status=Ended with error:
os="Error encountered.. Calls received so far: "+n;tm();
// Display a message on local console.
os=""; // You must return nothing into (os)
}
return; // Return back to server.
}
//--------------------------------- "Message received" calls ------------------------------
o1s=os; // Save (os) temporarely
//--- The "Bye" command ---
om("l"); // Change all char's to lower case.
if (os.IndexOf("bye")>-1) { // If message received was "Bye"
oc=' ';ob=true;return; // Send instruction to disconnect client.
}
else if (os.IndexOf("key:")>-1) { // If message received was "Key:"
oc='k';os="OK";return; // Mark it and return "OK".
}
else if (os.IndexOf("iv:")>-1) { // If message received was "IV:"
oc='i';os="OK";return; // Mark it and return "OK".
}
else if (oc=='k') { // If this is next trip following "Key:"
os="@";ks="temp";tm("Ead");JY=OY; // Decrypt binary data in OY[]. JY[]=output
oc=' ';os="OK";return; // Erase Mark and return "OK".
}
else if (oc=='i') { // If this is next trip following "IV:"
os="@";ks="temp";tm("Ead");KY=OY; // Decrypt binary data in OY[]. KY[]=output
oc=' ';os="OK";return; // Erase Mark and return "OK".
}
else { // Else:
os="@";tm("Esd"); // Decrypt encrypted data (must use OY[])
os="Client's decrypted message: "+os; // Display received message
tm();
os="And this is my confidential reply!";
tm("Ese"); // Encrypt message to be sent as text data
os="@";return; // Send the encrypted data as binary.
}
}
catch {
os="Error has been detected while processing your command.";
return; // In case of error, inform client.
}
}
}
CLIENT:
=======
public class tc:pcs {
public override void init() {
tia=toa="t";
base.init();
}
public override void run() {
cls="r0";fns="trb14";tm("c"); // Set font,color, clear screen.
os=" ENCRYPTED COMMUNICATION WITH OUR SERVER\n";tm();
fns="trb12"; // Display title, Change font
uhs="localhost";upi=55000;nm("to"); // Open connection with local server listening
// at port 55000
nm("tr"); // Read server response
if (os.IndexOf("PKey")>-1) { // If message received was the public key:
os=os.Substring(os.IndexOf(":")+1); // Eliminate the label.
kys=os; // Assign public key to (kys)
tm("Esk"); // Get new Key and IV for symmetric encryption.
//----------------------- Displaying Symmetric Encryption Keys -------------------------
os="";tm();cls="b0";
os="KEY AND IV BEFORE BEING ECRYPTED BY CLIENT:";tm();
cls="S9";os="KEY: ";tm("d"); // Display the key
for (n=0;n< JY.Length;n++) {os=" "+JY[n];tm("d");}
os="";tm();os="IV : ";tm("d"); // Display the IV
for (n=0;n< KY.Length;n++) {os=" "+KY[n];tm("d");}
os="";tm();tm();cls="b0"; // Skip a line
//---------------------------------------------------------------------------------------
os="Key:";nm("tw");nm("tr"); // Send the message "Key:" and read reply
OY=JY;os="@";ks="*s";tm("Eae"); // Encrypt the key binary data using the public
// key in (kys)
os="@";nm("tw");nm("tr"); // Send the binary encrypted data. Read reply
os="IV:";nm("tw");nm("tr"); // Send the message "IV:" and read reply
OY=KY;os="@";ks="*s";tm("Eae"); // Encrypt the IV binary data using the public
// key in (kys)
os="@";nm("tw");nm("tr"); // Send the binary encrypted data. Read reply
}
os="This is my secret message!"; // Message to be sent to server
string o1s=os; // Save message temporarely.
os="Message to be sent to server: "+o1s;tm();
os=o1s;tm("Ese"); // Display message then encrypt it as text
os="@";nm("tw");nm("tr"); // Send binary encrypted data. Read reply.
os="@";tm("Esd"); // Decrypt encrypted data.
os="Decrypted Server's message: "+os;tm(); // Display decrypted message.
os="";tm(); // Skip one line.
os="Bye";nm("tw"); // Logoff.
nm("tc"); // Close connection
}
}
===============================================================================================
Here is what you see on Server's console:
C:\pcs>ts
To Stop Server Press [Control][Break]
Ready for calls.... Calls received so far: 0
Server Connected... Calls received so far: 1
Client's decrypted message: This is my secret message.
Ready for calls.... Calls received so far: 1
And Here is what you see at the Client:

===============================================================================================
DOING IT ON THE MULTI-THREAD SERVER:
===================================
In the previous example, we have encrypted the communication between client and single-thread
server. This time, we are going to do the same using the multi-thread TCP server. You know that
the multi-thread TCP server each time its status change and each time it receives a message from
client, calls the logic method ServerLogic() which is included into class (TLogic) The method
receives three parameters, a string, an integer and an object of class (pcs.RxTx) You know enough
about the string and the integer. The object is what we'll be discussing here:
Class RxTx:
-----------
This class handles the reception and transmission of data with the client. It's also the one
which calles your prepared logic method in class TLogic to know what to do. The instance of class
RxTx which your method receives is unique for the thread you are serving, just like class
(TLogic). So, you need not to worry when you use variables associated with that object. The
public variables which you can access are (assuming that rt is the object's reference name):
rt.OY The byte array of class RxTx which can be used to send binary data to or receive binary
data from client.
rt.tcp The TcpClient object reference which the current thread handles.
With (rt.OY) you can operate on binary data and can also send binary data to client. With
(rt.tcp) you have all the power to do any operation which PC# does not do for you. You can even
send the reply to the client by yourself. Whenever you like to send the reply by yourself, you
must return the instruction "#n" to the server to stop it from sending another reply. We are going
to see how to do this in the next example.
Which var's to define at the top of class (TLogic):
---------------------------------------------------
Each thread handles one client from the moment a connection is established with the client to
the moment the client is disconnected.
In the previous example, we used the char variable (oc) for the purpose of memorizing what the
last message received was in order to know what the current binary data represents. We are going
to do the same here, so we need to define var (oc) at the top.
Normally, when you are using the multi-thread server, you write your code in C# directly without
using PC# methods. In the following example, we are going to create an instance of class (pcs)
to use within the ServerLogic() method. This will allow us to use PC#'s encryption and decryption
methods.
===============================================================================================
Example 13: Repeat example 4 of the "Security" chapter making it demonstrate the encryption of
actual communication between a client and server. Use the multi-thread TCP server this time.
Show also how to use class RxTx's object to send the last message to the client directly
without server's help.
===============================================================================================
SERVER
======
//assembly pcsut.exe
public class ts:pcsut { // Server class extends (pcs)
public override void run() {
cm("fe"); // Eliminate form.
cls="r0";dm("ccf"); // Change Console color to red
os="To Stop Server Press [Control][Break]";tm();
cls="S9";dm("ccf"); // Display message. Restore black color.
upi=55000;urs="";nm("tsm"); // Start TCP server using port 55000. Listen to all
} // available addresses.
}
CLIENT:
=======
public class tc:pcs {
public override void init() {
tia=toa="t";
base.init();
}
public override void run() {
cls="r0";fns="trb14";tm("c"); // Set font,color, clear screen.
os=" ENCRYPTION WITH THE MULTI-THREAD SERVER\n";tm();
fns="trb12"; // Display title, Change font
uhs="localhost";upi=55000;nm("to"); // Open connection with local server listening
// at port 55000
nm("tr"); // Read server response
if (os.IndexOf("PKey")>-1) { // If message received was the public key:
os=os.Substring(os.IndexOf(":")+1); // Eliminate the label.
kys=os; // Assign public key to (kys)
tm("Esk"); // Get new Key and IV for symmetric encryption.
//----------------------- Displaying Symmetric Encryption Keys -------------------------
os="";tm();cls="b0";
os="KEY AND IV BEFORE BEING ENCRYPTED BY CLIENT:";tm();
cls="S9";os="KEY: ";tm("d"); // Display the key
for (n=0;n< JY.Length;n++) {os=" "+JY[n];tm("d");}
os="";tm();os="IV : ";tm("d"); // Display the IV
for (n=0;n< KY.Length;n++) {os=" "+KY[n];tm("d");}
os="";tm();tm();cls="b0"; // Skip a line
//---------------------------------------------------------------------------------------
os="Key:";nm("tw");nm("tr"); // Send the message "Key:" and read reply
OY=JY;os="@";ks="*s";tm("Eae"); // Encrypt the key binary data using the public
// key in (kys)
os="@";nm("tw");nm("tr"); // Send the binary encrypted data. Read reply
os="IV:";nm("tw");nm("tr"); // Send the message "IV:" and read reply
OY=KY;os="@";ks="*s";tm("Eae"); // Encrypt the IV binary data using the public
// key in (kys)
os="@";nm("tw");nm("tr"); // Send the binary encrypted data. Read reply
}
os="Server, why are you so happy?"; // Message to be sent to server
string o1s=os; // Save message temporarely.
os="Message to be sent to server: "+o1s;tm();
os=o1s;tm("Ese"); // Display message then encrypt it as text.
os="@";nm("tw");nm("tr"); // Send binary encrypted data. Read reply.
os="@";tm("Esd"); // Decrypt encrypted data received.
os="Decrypted Server's reply: "+os;tm(); // Display decrypted message.
os="";tm(); // Skip one line.
os="Bye";nm("tw"); // Logoff.
nm("tc"); // Close connection
}
}
LOGIC CLASS:
============
//assembly pcsut.exe
public class TLogic:pcsut.ITLogic { // Logic class implements interface pcs.ITLogic
char oc; // Define var (oc) as discussed.
pcs p=new pcs(); // Create an instance of class (pcs)
//----------------- Method ServerLogic (Contains logic to be used by server) ----------------
public string ServerLogic (string os,int counter,pcsut.RxTx rt) {
// IN:os=Message received or status code If call was for status change, (os) will contain:
// "*l", "*c", "*s" or "*e" meaning Listening, Connected, Stopped or Ended with Error.
// counter: Connection counter updated by server.
// Object of class RxTx.
// OUT:os=Message to be sent or instruction code. If instructions, (os) will contain:
// "#d", "#s" or "#n" meaning "disconnect caller", "stop" or "Send no reply".
if (os.Length<1) return os; // If received empty string return it as is
string o1s=os; // Keep a copy of original (os)
//----------------------------------- Status change calls ---------------------------------
if (os.Length==2 && os.Substring(0,1)=="*") {
os=os.Substring(1,1); // If this was a status change call, get status code
if (os=="c") { // If status=Connected:
Console.WriteLine("Connections: "+counter);
// Display a message on local console.
p.ks="temp";p.tm("Eak"); // Generate asym. key-pair, store into container
os="PKey:"+p.os; // "temp". Send returned public key to client.
}
else if (os=="l" || os=="s" || os=="e") {
os=""; // Return nothing for all other 3 status codes.
}
return os; // Return back to server.
}
//-------------------------------- "Message received" calls -------------------------------
try {
//--- The "Bye" command ---
os=os.ToLower(); // Change all char's to lower case.
if (os.IndexOf("bye")>-1) { // If message received was "Bye"
oc=' ';return "#d"; // Send instruction to disconnect client.
}
else if (os.IndexOf("key:")>-1) { // If message received was "Key:"
oc='k';return "OK"; // Mark it and return "OK".
}
else if (os.IndexOf("iv:")>-1) { // If message received was "IV:"
oc='i';return "OK"; // Mark it and return "OK".
}
else if (oc=='k') { // If this is next trip following "Key:"
p.OY=rt.OY; // Assign encrypred key data to (p.OY)
p.os="@";p.ks="temp";p.tm("Ead"); // Decrypt binary data in p.OY[].
p.JY=p.OY; // Assign output to (p.JY)
oc=' ';return "OK"; // Erase Mark and return "OK".
}
else if (oc=='i') { // If this is next trip following "IV:"
p.OY=rt.OY; // Assign encrypred IV data to (p.OY)
p.os="@";p.ks="temp";p.tm("Ead"); // Decrypt binary data in p.OY[].
p.KY=p.OY; // Assign output to (p.KY)
oc=' ';return "OK"; // Erase Mark and return "OK".
}
else { // Else:
p.OY=rt.OY; // Assign encrypred message data to (p.OY)
p.os="@";p.tm("Esd"); // Decrypt encrypted data (must use OY[])
Console.WriteLine("Client's decrypted message: "+p.os);
// Display received message
TcpClient tcp=rt.tc; // Get reference to the TcpClient object
NetworkStream ns=tcp.GetStream(); // Obtain ref. to NetworkStream object.
//---- Reply will be encrypted then sent directly to client bypassing server ----
p.os="They have done all the work for me!";
p.tm("Ese"); // Encrypt reply to be sent as text data
ns.Write(p.OY,0,p.OY.Length); // Send encrypted data directly to client.
return "#n"; // Instruct server to send no reply to client.
}
}
catch {
return "Error has been detected while processing your command.";
// In case of error, inform client.
}
}
}
===============================================================================================