|
Though
on the face of it the Internet and World Wide Web appear fairly
simple, if you scratch the surface you would appreciate that
it is built upon complex protocols, networking technologies
and programs. .NET attempts to reduce this complexity for
the programmer and therefore is able to impact the Web and
network programming in a major way.
Network programming
Network programming under .NET is quite similar to reading
and writing files on local disk. Network applications are
written using the client-server model. In this model the communication
is carried out using entities called sockets.
Sockets are nothing but software abstractions that are used
to represent the end points of a connection between two machines.
For any given connection there is one socket on the client
and one socket on the server. A program can read from a socket
or write to a socket in a manner that is similar to File-IO.
The socket-based communication can be of two types, namely,
Connection-oriented and Connectionless. Of these, the connection-oriented
service uses the popular Transmission Control Protocol (TCP),
whereas the connectionless service uses the User Datagram
Protocol (UDP). In this article we will concentrate on the
TCP protocol.
To be able to communicate between any two machines in a network,
there must be a unique way to identify them. This is achieved
using the IP (Internet Protocol) address of the machine. If
we mention a machine name it ultimately gets converted into
an IP address. However, it is possible for more than one application
to be using a network connection at the same time. Therefore
each application must have a unique ID so that the client
can indicate which application it is looking for. This unique
ID is called port number. Thus the IP address and port number
represent the first and second level of addressing respectively.
.NET provides several classes and interfaces organised under
the namespace System.Net.Sockets to help us write Connectionless
and Connection-oriented networking applications. Typically
in a Connection-oriented service, a server waits for a connection
request from the client. This waiting is generally done in
a loop. Once the server gets a request a connection is set
up between the server and the client. The end points of this
connection are sockets. The functionality of these sockets
has been wrapped inside the TcpListener and TcpClient
classes present in the System.Net.Sockets namespace.
Hence to carry out Connection-oriented communication between
two applications running on same/different machines we need
to create objects of these classes. The TcpListener
object is used to listen to the requests from the client.
The TcpClient object is used to establish a connection
between the client and the server. Let us now see how to use
the classes in this namespace to build an application.
We have designed this application to transfer a file requested
by the client from server to client. The same application
acts as a client as well as a server. The interface of this
application is shown in Figure 1.

The following table shows the controls and their Names.
| Control |
Name |
| Server
Text Box |
Tserver |
| Port
Text Box |
tport |
| Listen
As Server Button |
bserver |
| Connect
As Client Button |
bclient |
| File
Name Text Box |
fname |
| Open
Button |
bopen |
| TextBox |
text |
Both the users have to start the same application. Out of
the two, one should listen as server and another should connect
as client. It is necessary to listen as server before connecting
as a client, otherwise the client would get an exception.
To be able to listen as server, the user has to enter the
port number (any integer value) and click the Listen
As Server button. The client must enter both the server
name (name of machine on which the server application is running)
and the same port number and then click the Connect
As Client button. The client now can enter the file
name with entire path in the Enter File Name text
box and click the Open button. As soon as the
client clicks the Open button, a request to send
the specified file is sent to the server and the file contents
are received back from the server.
Let us now add the handlers and write the required code in
them. First of all we would add the Click event handler
for the Listen As Server button. The code of the
handler is given below.
private void bserver_Click (object sender, System.EventArgs e)
{
int portno = Convert.ToInt16(port.Text);
TcpListener l = new TcpListener(portno);
l.Start();
tc = l.AcceptTcpClient();
st = tc.GetStream();
bserver.Enabled = false;
recvthread r = new recvthread(st);
Thread t = new Thread (new ThreadStart (r.sendfile));
t.IsBackground = true;
t.Start();
}
Here, we have first obtained the port number. We have then
created an object of the TcpListener class and stored
the port number in it. We have then called the Start()
method of the TcpListener class. This method would
wait in a loop (listening) for a connection request from the
client. The method would listen on the port number assigned
to the TcpListener object. Here were effectively
blocking on the Start() method until a request comes
in from the client We have then called the AcceptTcpClient()
method to accept the connection request and obtain an object
of the TcpClient class. Hence we need to create a reference
tc of the type TcpClient as the data member of the
Form1 class. We have then called the GetStream()
method using the tc reference to obtain a reference to the
object of the NetworkStream class. This object would
be used to write into the socket. To collect the reference
we need to create a reference st of the type NetworkStream
as the data member of the Form1 class. We have disabled
the Listen As Server button so that the user should
not click it again.
The server and client can exchange messages as soon as the
connection is established. The messages sent by both the server
and client would get written to the stream. We do not receive
any notification when the data is written to the stream. Hence
we need to continuously check whether the data has been written
to the stream or not so that we can read it. If we dont
start another thread and wait for the messages in the current
thread that has displayed the form, we would not be able to
interact with the form. Hence it is necessary to start a thread
in which we can read the data from the stream. We also need
to make the thread a background thread because as soon as
the application closes, we also want the thread to stop. The
thread would need the NetworkStream reference to read
the messages from the stream. We cannot pass these parameters
directly to the sendfile() method that is used for
reading and sending file contents in the thread as the ThreadStart
delegate doesnt permit it. Hence we have wrapped the
sendfile() method in the recvthread class and
used its constructor to initialise the parameter needed by
the sendfile() method. To the one-argument constructor
of the recvthread class, we have passed the reference
to the NetworkStream object (obtained using the GetStream()
function). Next, we have started the thread to read the data
received from the socket. For what follows after this, tune
in next week!
 |
Yashavant
Kanetkar, one of the first Express Computer columnists,
is an established software expert, speaker and author
with several best-sellers to his credit, including titles
like “Let Us C” and the “Fundas” series. Contact him at
kanet@nagpur.dot.net.in |
|