User Datagram Protocol Exercise

powered by FreeFind

Modified: 

Protocols Overview

The data link layer can provide reliable and unreliable data transfer between the network layer of hosts. Several protocols based on datagrams are discussed and implemented using C by Tannenbaum though the underlying physical layer services are not implemented, required for actual experimentation. The simpler C protocol algorithms (Protocol 1-4) were implemented in Java using datagrams as the underlying protocol. As many of you noted, few if any errors were observed on the LAN, making the unreliable datagram in fact reasonably reliable. Even Protocol 2, which could deadlock on errors rarely would given the low error rate typical of LANs. As an example of a familiar program, Protocol 1 has been implemented below using datagrams directly. The key elements of Java for inserting datagrams onto and receiving datagrams from the network are discussed below.

Python Datagram Services

A key advantage of Python for network applications is the relative simplicity of communication using datagram and connection services. The following discusses the key parts of Java for implementing datagram service.

Port - A workstation is uniquely identified by its IP number such as 149.160.51.113 associated with an NIC. Even though only one NIC is used the host may be communicating with multiple sites simultaneously. To maintain each communication separately, datagrams are sent and received through unique (to the host)  ports. A few applications, such as SMTP (port 25), HTTP (port 80), FTP, etc. have well-known port numbers that are generally reserved. In our example, we used one port to send (sendPort=999) and another to receive (receivePort=666). Though it is possible to use one bi-directional port, because the sender and receiver are running on the same host, each bi-directional communication must use a different port number, that is only one use of a port number is allowed per computer host. It is important to note that the sender must send to the receiver port number in order for the two to communicate. In the chat implementations below, two different ports are used when the same machine is used for both sides of the chat.

Socket - A datagram socket is somewhat similar to a file handle except that provides a bi-directional access to send or receive datagrams via the network rather than a file system. Under TCP/IP it must be associated with a unique port number for that host. receiverSocket.bind(('',999)) creates a new socket identified with port 999, the object ds can be used to send or receive datagram packets through port 999.


Protocol 1 

Protocol 1 from Tannenbaum has a weakness in that communication is simplex with no coordination between sender and receiver to prevent overflow of the receiver. The following implements Protocol 1 using datagrams. The diagram at right illustrates the port communication.

Sender                                                                               Receiver
# Protocol 1 sender using Python datagrams

from socket import *

senderSocket=socket(AF_INET, SOCK_DGRAM)

while True :
   userIn=raw_input()         # from_network
   if not userIn : break        # to_physical
   senderSocket.sendto(userIn, ('localhost', 999))
senderSocket.close()
# Protocol 1 receiver using Python datagrams

from socket import *

receiverSocket=socket(AF_INET, SOCK_DGRAM)
receiverSocket.bind(('',999))

while True :                   # from_physical
   data, address = receiverSocket.recvfrom(1024)
   if not data : break
   print data                   # to_network
receiverSocket.close()

chat0 Python

chat0.py
# chat0

from socket import *

ioSocket=socket(AF_INET, SOCK_DGRAM)
ioPort = 111
receiverPort=ioPort
toName = 'localhost'

if toName == 'localhost' : receiverPort = 222

try :
   ioSocket.bind(('',ioPort))
except Exception :
   ioPort = 222
   receiverPort = 111
   ioSocket.bind(('',ioPort))

print 'chat0 on port ', ioPort, '. Blank line to quit.'

while True :
   userIn = raw_input()
   ioSocket.sendto(userIn, (toName, receiverPort))
   data, address = ioSocket.recvfrom(1024)
   if not data : break
   print data
ioSocket.close()

Problems - Obviously the chatters should not be forced to take turns chatting.
Solution - The reasonable solution is to create separate threads of execution for sending and receiving packets allowing multiple packets to be sent from a single, talkative chatter.


chat1

Improvement over chat0 is that it can receive and send at any time using two separate threads, the main thread for sending and a new thread for the receiving. Python supports lightweight threads that execute pseudo-parallel with the main thread. The main thread will continue to handle user typing, a separate thread will handle receiving and displaying datagrams; both threads operate independently avoiding the lockstep, turn-taking of the chat0. Daemon threads are used because they terminate when the main thread terminates.

chat1.py
# chat1

from socket import *
import threading
class receiver(threading.Thread) :  # Receiver thread
   def __init__(self, socket ):
      threading.Thread.__init__(self)
      self.SOCKET=socket
      self.setDaemon(True)             # Daemon threads stop with main thread

   def run(self) :
      while True :                           # Receive in daemon thread
            data, address = self.SOCKET.recvfrom(1024)
            if not data : break
            print address, ' ', data
      self.SOCKET.close()
ioSocket=socket(AF_INET, SOCK_DGRAM)
ioPort = 111
receiverPort=ioPort
toName = 'localhost'

if toName == 'localhost' : receiverPort = 222

try :
   ioSocket.bind(('',ioPort))
except Exception, msg :
   ioPort = 222
   receiverPort = 111
   ioSocket.bind(('',ioPort))

print 'chat1 on port ', ioPort, '. Blank line to quit.'
receiver(ioSocket).start()              # Create receiver thread and start
while True :                                 # Send in main thread
   userIn = raw_input()
   if not userIn : break
   ioSocket.sendto(userIn, (toName, receiverPort))
ioSocket.close()

Problem - While two chatters can chat to one another, assuming that they each knew the others IP address, can a new chatter join the chat group? Unfortunately no since new chatters are not learned and remembered as they make contact. Currently the chatter host must be designated in the Python code (i.e. toName='localhost'). 

Consider that A contacts B and B contacts A, then A and B can chat. But if C contacts A, C can chat with A but A can't chat with C!

Solution - An apparently reasonable solution is to add the IP of any new chatters making contact to a chatters list. Chat packets are then sent to all chatters in the list. If A and B are chatting A maintains a list of: A(B) and B the list of chatters B(A). When C contacts A, the lists are now: A(B,C), B(A), C(A).

Exercise 1

  1. Propose a solution,
  2. implement the solution, the instructor will help.
  3. Name the new program file:
  4. test.
  5. One solution.


Problem - While several chatters can now chat to one another, and a new chatter can chat with one of the original chatters, the new chatter does not chat with other chatters in the group. Consider that A contacts B and B contacts A, then A and B can chat. When C contacts A, A adds C to a list of chatters that it will send packets to but A does not send B chat from C or C chat from B. The lists maintained would be: A(B,C), B(A), C(A).

Solution - A apparently reasonable solution is to add the IP of any new chatters making contact to a list and to forward to all chatters in the list any chat received. To avoid loops an exception is made not to forward to the sender of the chat. If A is contacted by B and C, the lists become A(B,C), B(A), C(A). When C chats with A, A forwards any messages to B and will do the same for B chatting with A. A could serve as the contact point for all chatters, effectively acting as a chat server might. Or two chatters that act as servers (e.g. A and C) might contact each and other chatters contact the server (e.g. A contacted by B and C contacted by D). The lists would be: A(B,C), B(A), C(A,D), D(C). The corresponding graph would appear as at right where B chat with A would be forwarded to C which forwards to D.

Two requirements are necessary to avoid loops:

  1. A chatter can contact only one other chatter. For example, C contacts host A when starting execution by: c:\python23\python chat2.py A
  2. Chat is forwarded to all chatters except the one sending the chat. In the graph example, A forwards to all known chatters except B, where B is the original chatter.

Exercise 2

  1. Propose a solution,
  2. implement the solution, the instructor will help.
  3. Name the new program file and class:
  4. test.
  5. One solution. Running two chatters on one host will create a loop and produce infinite output.

 

Java Datagram Services

A key advantage of Java for network applications is the relative simplicity of communication using datagram and connection services. The following discusses the key parts of Java for implementing datagram service.

Port - A workstation is uniquely identified by its IP number such as 149.160.51.113 associated with an NIC. Even though only one NIC is used the host may be communicating with multiple sites simultaneously. To maintain each communication seperately, datagrams are sent and received through unique (to the host)  ports. A few applications, such as SMTP (port 25), HTTP (port 80), FTP, etc. have well-known port numbers that are generally reserved. In our example, we used one port to send (sendPort=999) and another to receive (receivePort=666). Though it is possible to use one bi-directional port, because the sender and receiver are running on the same host, each bi-directional communication must use a different port number, that is only one use of a port number is allowed per computer host. It is important to note that the sender must send to the receiver port number in order for the two to communicate. In the chat implementations below, two different ports are used when the same machine is used for both sides of the chat.

Socket - A datagram socket is somewhat similar to a file handle except that provides a bi-directional access to send or receive datagrams via the network rather than a file system. Under TCP/IP it must be associated with a unique port number for that host. DatagramSocket ds =new DatagramSocket(999) creates a new socket identified with port 999, the object ds can be used to send or receive datagram packets through port 999.

Packet - The datagram information is contained in a packet that is sent or received through a socket.

InetAddress - The IP address representation of a host.

  • InetAddress(getLocalHost()) returns the address of the host machine executing the statement.
  • InetAddress.getByName("www.sun.com") returns the address of the host www.sun.com.
  • InetAddress.getByName("149.160.23.145") returns the address of the host 149.160.23.145.

Protocol 1 

Protocol 1 from Tannenbaum has a weakness in that communication is simplex with no coordination between sender and receiver to prevent overflow of the receiver. The following implements Protocol 1 using datagrams. The diagram at right illustrates the port communication.

Sender
// Protocol 1 sender using Java datagrams, Tanenbaum

 import java.net.*;
 import java.io.*;

 class p1sender {
   public static void main(String args[]) throws Exception {

     byte senderBuffer[] = new byte[128];                   // Packets 128 bytes long
     String toName, userIn;
     BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
     DatagramSocket senderSocket = new DatagramSocket(999); 
                                                                                // Create socket for sending
     if (args.length > 0) toName = args[0];                 // IP or DNS from command line
     else                 toName = "localhost";

     while ((userIn=in.readLine())!=null ){                   // Read standard input
        senderBuffer=userIn.getBytes();                      // Convert from string to byte array
                                                                               // Send datagram packet out socket
        senderSocket.send(new DatagramPacket( senderBuffer, senderBuffer.length,
                                                InetAddress.getByName(toName), 666));
     }       
   }
 }
Receiver
// Protocol 1 receiver using Java datagrams, Tanenbaum 

 import java.net.*;

 class p1receiver {
   public static void main(String args[]) throws Exception {

     byte receiveData[] = new byte[128];

     DatagramSocket receiveSocket = new DatagramSocket(666);   
                                                                                         // Create socket for receiving
     DatagramPacket receivePacket = new DatagramPacket(receiveData, 128);

     while (true) {
        receiveSocket.receive(receivePacket);                  // Wait for datagram packet to arrive
                                                                                         // Print packet contents as String
        System.out.println(new String(receivePacket.getData(), 0, receivePacket.getLength()));
     }   
   }
 }

Protocol 1 Sender and Receiver Comparison

// Protocol 1 sender using Java datagrams, Tanenbaum

import java.net.*;
import java.io.*;

class p1sender {
 public static void main(String args[]) throws Exception {

  byte senderBuffer[] = new byte[128];  
  String toName, userIn;
  BufferedReader in = new BufferedReader(
                        new InputStreamReader(System.in));
  DatagramSocket senderSocket = new DatagramSocket(999);

  if (args.length > 0) toName = args[0];  
  else                 toName = "localhost";

  while ((userIn=in.readLine())!=null ){        
    senderBuffer=userIn.getBytes();     
                                          
    senderSocket.send(
       new DatagramPacket( senderBuffer, senderBuffer.length,
               InetAddress.getByName(toName), 666));
  }       
 }
}
// Protocol 1 receiver using Java datagrams, Tanenbaum 

import java.net.*;

class p1receiver {
 public static void main(String args[]) throws Exception {

   byte receiveData[] = new byte[128];

   DatagramSocket receiveSocket = new DatagramSocket(666);  
   DatagramPacket receivePacket = new DatagramPacket(receiveData, 128);

   while (true) {
     receiveSocket.receive(receivePacket);           
                                                         
     System.out.println(
         new String(
             receivePacket.getData(), 0, receivePacket.getLength()));
   }   
 }
}

simpleChat Java

simpleChat.java
import java.net.*;
import java.io.*;

public class simpleChat {

   public static void main(String args[]) throws Exception {
   
    DatagramSocket ioSocket;
    String toName, userIn;
    byte sendBuffer[]    = new byte[128];
    byte receiveBuffer[] = new byte[128];
    DatagramPacket sendPacket = new DatagramPacket(sendBuffer, 128);
    DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, 128);
    BufferedReader in = new BufferedReader(
                                            new InputStreamReader( System.in));

    int ioPort           = 111, receiverPort = ioPort;

    if (args.length > 0) toName = args[0];  
    else                       toName = "localhost";
    if (toName.equals("localhost"))                        // Use port 111 or 222 whether
        receiverPort = 222;                                     // chatting with localhost or remote
    try { ioSocket = new DatagramSocket(ioPort); }
    catch (Exception e) {                                       // Switch ports when port 111 in use
        ioPort = 222; receiverPort = 111;
        ioSocket = new DatagramSocket(ioPort);
    }

    System.out.println("simpleChat on port " + ioPort + ". Ctrl Z to quit.");

    while ((userIn=in.readLine())!=null) {                 // Read user input until Ctrl Z
        sendBuffer= userIn.getBytes();                      // Convert string to byte array
        sendPacket = new DatagramPacket( sendBuffer, sendBuffer.length,
                                           InetAddress.getByName(toName), receiverPort);
        ioSocket.send(sendPacket);                        // Send packet
        ioSocket.receive(receivePacket);                // Wait to receive packet
                                                                              // Print contents of received packet
        System.out.println( "Received " + new String(receivePacket.getData(), 
                                               0, receivePacket.getLength()));
    }
   }
}

Problems - Obviously the chatters should not be forced to take turns chatting.
Solution - The reasonable solution is to create separate threads of execution for sending and receiving packets allowing multiple packets to be sent from a single, talkative chatter.


chat

Improvement over simpleChat is that it can receive and send at any time using two separate threads, the main thread for sending and a new thread for the receiving.

chat.java
import java.net.*;
import java.io.*;

public class chat {

   public static void main(String args[]) throws Exception {
   
    DatagramSocket      ioSocket;
    String                      toName         = "localhost";
    String                      userIn;
    byte                        sendBuffer[]  = new byte[128];
    DatagramPacket      sendPacket   = new DatagramPacket(sendBuffer, 128);
    BufferedReader        in                  = new BufferedReader(
                                                             new InputStreamReader(System.in));
    int ioPort                                       = 111, receiverPort = ioPort;

    if (args.length > 0) toName = args[0];  
    else                 toName = "localhost";
    if (toName.equals("localhost"))             // Use two ports for localhost
        receiverPort = 222; 
    try { ioSocket = new DatagramSocket(ioPort); }
    catch (Exception e) {
        ioPort = 222; receiverPort = 111;
        ioSocket = new DatagramSocket(ioPort);
    }

    System.out.println("chat on port " + ioPort + ". Ctrl Z to quit.");
    new receiver(ioSocket);                          // Start receiver thread
    while ((userIn=in.readLine())!=null) {       // Read user input until Ctrl Z
        sendBuffer = userIn.getBytes();          
        sendPacket = new DatagramPacket( sendBuffer, sendBuffer.length,
                                    InetAddress.getByName(toName), receiverPort);
        ioSocket.send(sendPacket);            // Send datagram
    }
    System.exit(0);                                      // Exit, stopping receiver
   }
}
class receiver implements Runnable {

    DatagramSocket ioSocket;

    receiver(DatagramSocket ioSocket) {
      this.ioSocket = ioSocket;
      new Thread(this).start();                      // Start thread at run()
    }

    public void run() {
      byte receiveBuffer[] = new byte[128];
      DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, 128);

      while(true) {                              
        try { ioSocket.receive(receivePacket); }// Wait for datagram
        catch (Exception e) {}
        System.out.println( "Received " + new String(receivePacket.getData(), 
                                                0, receivePacket.getLength()));
      }
    }
}

Problem - While two chatters can chat to one another, assuming that they each knew the others IP address, can a new chatter join the chat group? Unfortunately no since new chatters are not learned and remembered as they make contact. Currently only the chatter host designated on the command line is contacted (i.e. java -cp . 149.160.24.23 ). 

Consider that A contacts B and B contacts A, then A and B can chat. But if C contacts A, C can chat with A but A can't chat with C!

Solution - An apparently reasonable solution is to add the IP of any new chatters making contact to a chatters list. Chat packets are then sent to all chatters in the list. If A and B are chatting A maintains a list of: A(B) and B the list of chatters B(A). When C contacts A, the lists are now: A(B,C), B(A), C(A).

Exercise 1

  1. Propose a solution,
  2. implement the solution, the instructor will help.
  3. Name the new program file and class:
  4. test.
  5. One solution.


Problem - While several chatters can now chat to one another, and a new chatter can chat with one of the original chatters, the new chatter does not chat with other chatters in the group. Consider that A contacts B and B contacts A, then A and B can chat. When C contacts A, A adds C to a list of chatters that it will send packets to but A does not send B chat from C or C chat from B. The lists maintained would be: A(B,C), B(A), C(A).

Solution - A apparently reasonable solution is to add the IP of any new chatters making contact to a list and to forward to all chatters in the list any chat received. To avoid loops an exception is made not to forward to the sender of the chat. If A is contacted by B and C, the lists become A(B,C), B(A), C(A). When C chats with A, A forwards any messages to B and will do the same for B chatting with A. A could serve as the contact point for all chatters, effectively acting as a chat server might. Or two chatters that act as servers (e.g. A and C) might contact each and other chatters contact the server (e.g. A contacted by B and C contacted by D). The lists would be: A(B,C), B(A), C(A,D), D(C). The corresponding graph would appear as at right where B chat with A would be forwarded to C which forwards to D.

Two requirements are necessary to avoid loops:

  1. A chatter can contact only one other chatter. For example, C contacts host A when starting execution by: java -cp . chatpeer2 A
  2. Chat is forwarded to all chatters except the one sending the chat. In the graph example, A forwards to all known chatters except B, where B is the original chatter.

Exercise 2

  1. Propose a solution,
  2. implement the solution, the instructor will help.
  3. Name the new program file and class:
  4. test.
  5. One solution. Running two chatters on one host will create a loop and produce infinite output.

C++ Datagram Services on Windows

Most of the Java ideas transfer in some form to C, whether using Windows, Unix, or other operating system. However, changes are needed to adapt to the specific operating system, this only discusses Windows. The relevant points to running a UDP application such as the following simpleChat are:

Port - The concept of a port is common on all TCP/IP implementations whether Java or C. In our example, we used one port to send (ioPort) and receive on the local host. If both sides of the chat are on the same machine receivePort is a different number.

Socket - ioSocket = socket(AF_INET, SOCK_DGRAM,0); creates a new socket unidentified with any port. The varible ioSocket can be used to send or receive datagram packets after being bound to a port.

Binding - bind(ioSocket,(struct sockaddr*)&local,sizeof(local) ); binds ioSocket to the port defined in data structure local. The socket can now be used for sending and receiving datagrams.

Packet - The datagram information is contained in a packet that is sent or received through a socket.

simpleChat C++

simpleChat.cpp
//      simpleChat.cpp - Use: simpleChat <IP> or <DNS>
//      Visual C++ Project | Settings | Link | Object/Library modules | ws2_32.lib

#include "stdafx.h"
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <iostream.h>

int main(int argc, char* argv[])
{
  char                         buffer[128];
  unsigned short          ioPort = 111, receiverPort = ioPort;
  int                            retval, receiverlen=128;
  unsigned int             addr=0;
  struct sockaddr_in    local, receiver;
  struct hostent          *host;
  WSADATA                wsaData;
  SOCKET                   ioSocket;
  char                         localName[128];

  WSAStartup(0x202,&wsaData);                     // Startup

  gethostname(localName, sizeof(localName));      // Check if chatting with self
  host = gethostbyname(localName);
  strcpy(localName, host->h_name);
  host = gethostbyname(argv[1]);
  if ((host && strcmp(localName, host->h_name) == 0) || 
               strcmp(argv[1], "127.0.0.1") == 0)
          receiverPort = 222;                     // Chatting with self, use two ports

  if (!host) addr = inet_addr(argv[1]);           // IP used instead of a name?

  if ((!host)  && (addr == INADDR_NONE) ) {       // Failed to resolve name or IP
      cout << "Unable to resolve " << argv[1] << '\n';
      return -1;
  }
  if (host != NULL) {                             // Copy receiver info
      memcpy(&(receiver.sin_addr),host->h_addr,host->h_length);
      receiver.sin_family = host->h_addrtype;
  }
  else {
      receiver.sin_addr.s_addr = addr;
      receiver.sin_family = AF_INET;
  }
  receiver.sin_port = htons(receiverPort);

  local.sin_family = AF_INET;
  local.sin_addr.s_addr = INADDR_ANY;
  local.sin_port = htons(ioPort);

  ioSocket = socket(AF_INET, SOCK_DGRAM,0);

  if (ioSocket == INVALID_SOCKET){
     cout << "socket() failed with error " << WSAGetLastError() << '\n';
     return -1;
  }

  if (bind(ioSocket,(struct sockaddr*)&local,sizeof(local) ) == SOCKET_ERROR) {
      unsigned short temp = ioPort;        // Try switching ports for chatting with self
      ioPort = receiverPort;
      receiverPort = temp;
      local.sin_port = htons(ioPort);
      receiver.sin_port = htons(receiverPort);
      if (bind(ioSocket,(struct sockaddr*)&local,sizeof(local) ) == SOCKET_ERROR) {
         cout << "bind() failed with error " << WSAGetLastError() << '\n';
         return -1;
      }
  }

  cout << argv[0] << " listening on " << ioPort << " protocol UDP\n";
  receiverlen = sizeof(receiver);

  while(cin >> buffer) {

     retval = sendto(ioSocket,buffer,strlen(buffer)+1,0,
                    (struct sockaddr *)&receiver,receiverlen);

     if (retval == SOCKET_ERROR)
        cout << "sendto() failed with error " << WSAGetLastError() << '\n';

     retval = recvfrom(ioSocket,buffer,sizeof(buffer),0,
                      (struct sockaddr *)&receiver,&receiverlen);

     cout << "Received " << buffer << "\n";
  }
}


VB Datagram Services

VB UDP is through the WinSock object described in Homework 6. A workstation is uniquely identified by its IP number such as 149.160.51.113 associated with an NIC. Though only one NIC is used the host may be communicating with multiple sites simultaneously. To maintain each communication seperately, datagrams are sent and received through unique (to the host)  ports. A few applications, such as SMTP (port 25), HTTP (port 80), FTP, etc. have well-known port numbers that are generally reserved. In our example, we used one port to send (sendPort) and another to receive (receivePort), even though it is possible to use one bi-directional port. It is important to note that the sender port number on one host must match the receiver port number on the other host in order for the machines to communicate. In the chat implementations below, two different ports are used when the same machine is used for both sides of the chat.

The key points and examples, assuming that the name of the WinSock object is WinSock1 are:

Protocol -   Winsock1.Protocol = sckUDPProtocol - Defines the protocol as UDP.

IP or DNS of remote host- WinSock1.RemoteHost = "localhost" - Defines the name of the remote host.

Local Port - WinSock1.Bind 111 - Binds to the local port 111.

Port of remote host - WinSock1.RemotePort = 222 - Port to send datagrams to on the remote host.

Private Sub WinSock1_DataArrival (ByVal bytesTotal As Long)
  Dim strData As String
  WinSock1.GetData strData
  txtReceive.Text = strData
End Sub
Packet - The datagram information is contained in a packet that is sent or received through the WinSock1 object.

simpleChat VB

Note that the following contains portions from the Microsoft VB 6.0 documentation.

  • Protocol description
  • Symetric, one version runs on each of two hosts.
  • Each host can send one character to the other at any time due to the event driven natural of VB.
  • Message is sent as raw text string. A message is not considered to be terminated by anything.
  • Protocol not terminated by anything.
  • UDP Basics
    In contrast to TCP, the UDP protocol doesn't require an explicit connection. To send data between two controls, three steps must be completed (on both sides of the connection):

    1. Set the RemoteHost property to the name of the other computer.
    2. Set the RemotePort property to the LocalPort property of the second control.
    3. Invoke the Bind method specifying the LocalPort to be used. (This method is discussed in greater detail below.)  Because both computers can be considered "equal" in the relationship, it could be called a peer-to-peer application. To demonstrate this, the code below creates a "chat" application that allows two people to "talk" in real time to each other:

    To create a UDP Peer

    1. Create a new Standard EXE project.
    2. Draw a Winsock control on the form , it will be named WinSock1 automatically. To place on toolbar:
    3. Add two TextBox controls to the form. Name the one txtSend, and the other txtReceive.
    4. Add the code below for Peer 1.
    UDP Peer 1 and 2
    ' UDP Peer 1

    Private Sub Form_Load( )
      WinSock1.RemoteHost = "localhost"
      Winsock1.Protocol = sckUDPProtocol
      WinSock1.RemotePort = 222    ' Port to connect to.
      WinSock1.Bind 111                  ' Bind to the local port.
    End Sub

    Private Sub txtSend_Change( )
    ' Send text as soon as it's typed.
        WinSock1.SendData txtSend.Text
    End Sub

    Private Sub WinSock1_DataArrival (ByVal bytesTotal As Long)
       Dim strData As String
       WinSock1.GetData strData
       txtReceive.Text = strData
    End Sub

    'UDP Peer 2

    Private Sub Form_Load( )
      WinSock1.RemoteHost = "localhost"
      Winsock1.Protocol = sckUDPProtocol
      WinSock1.RemotePort = 111    ' Port to connect to.
      WinSock1.Bind 222                  ' Bind to the local port.
    End Sub

    Private Sub txtSend_Change( )
    ' Send text as soon as it's typed.
        WinSock1.SendData txtSend.Text
    End Sub

    Private Sub WinSock1_DataArrival (ByVal bytesTotal As Long)
       Dim strData As String
       WinSock1.GetData strData
       txtReceive.Text = strData
    End Sub

    To create a second UDP Peer

    1. Run another copy of VB.
    2. Add a standard form to the project.
    3. Follow the same steps as above except reverse port assignments to allow running on one host

    To try the example, press F5 to run the project, and type into the txtSend TextBox on either form. The text you type will appear in the txtReceive TextBox on the other form.

    About the Bind Method
    As shown in the code above, you must invoke the Bind method when creating a UDP application. The Bind method "reserves" a local port for use by the control to receive datagram packets. For example, when you bind the control to port number 1001, no other application can use that port to "listen" for packets.

    The Bind method also features an optional second argument. If there is more than one network adapter present on the machine, the LocalIP argument allows you to specify which adapter to use. If you omit the argument, the control uses the first network adapter listed in the Network control panel dialog box of the computer's Control Panel Settings.

    When using the UDP protocol, you can freely switch the RemoteHost and RemotePort properties while remaining bound to the same LocalPort. However, with the TCP protocol, you must close the connection before changing the RemoteHost and RemotePort properties.


    Race game

    Peer configurations typically interact more freely than the interaction characterized by a client and server taking turns as exemplified by a Web browser and server. A simple example where either peer can initiate an action is given below as a racing game where a peer moves on a grid, each attempting to crash into the other first. In this particular example the peers are identical so only one program exists. While the command/response interaction model typical of a client/server is relatively simple to program it is inappropriate where high interactivity is required, as is this case where either peer should be able to make multiple moves without waiting on the other to move.

    A description of the racing game following unrestricted model.

     
    // Racer.java - Use: java -cp . Racer <IP or DNS>
    
    import java.net.*;
    import java.io.*;
    
    public class Racer {
            
       public static void main(String args[]) throws Exception {
          int ioPort                = 111, toPort = ioPort;
          String toName        = "localhost";
          DatagramSocket ioSocket;
          Race race;
                                                                          // If both on same machine
          if (args.length > 0)                                    // use two port numbers
              toName = args[0] == null ? "localhost" : args[0];
              if (toName.equals("localhost")) toPort = 222; 
              try { ioSocket = new DatagramSocket(ioPort); }
              catch (Exception e) {                            // 222 already receiverPort
                 ioPort = 222; toPort = 111;              // use 111 instead
                 ioSocket = new DatagramSocket(ioPort);
              }
    
              System.out.println("Racer listening on port " + ioPort);
    
              if (ioPort == 111) 
                  race = new Race('C', 0, 0, 'S', 2, 2);  // Start of race
              else
                  race = new Race('S', 2, 2, 'C', 0, 0);  // Start of race
    
              ReceiverThread receiver = new ReceiverThread(ioSocket, race);
              SenderThread sender = new SenderThread(ioSocket, toName, toPort, race);
       }
    }
    

    import java.net.*;
    import java.io.*;
    
    class SenderThread implements Runnable {
       DatagramSocket out;
       String toName;
    
       int toPort;
       Race race;
    
       public SenderThread(DatagramSocket out, String toName, int toPort, Race race) {
          this.out = out;
          this.toName = toName;
          this.toPort = toPort;
          this.race = race;
          new Thread(this).start();
       }
    
       public void run() {
          while(!race.over()) send();
       }
    
       public void send() {
          char c;
          byte sendBuffer[] = new byte[1];
          DatagramPacket sendPacket;
    
          try {   
              if (System.in.available() > 0 ) {
    
                  c=(char) System.in.read();
                  switch(c) {
                     case 'I': case 'J': case 'K': case 'M': 
                               sendBuffer[0] = (byte) c;
                               sendPacket = new DatagramPacket( sendBuffer, 1,
                                                InetAddress.getByName(toName), toPort);
                               out.send(sendPacket);
                               race.moveme(c);
                  }
               }
          }
          catch(Exception e) { }
      }
    }
    

    import java.net.*;
    import java.io.*;
    
    
    class ReceiverThread implements Runnable {
    
            DatagramSocket in;
            Race race;
    
            public ReceiverThread(DatagramSocket in, Race race) { 
                    this.in = in; 
                    this.race = race;
                    try { in.setSoTimeout(1000); } catch(Exception e) {};
                    new Thread(this).start();
            }
    
            public void run() {
                    while(!race.over()) receive();
            }
    
            public void receive() {
                    char c;
                    byte receiveBuffer[] = new byte[1];
                    DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, 1);
                    try {   
                            in.receive(receivePacket);
                            c = (char) receiveBuffer[0]; 
                            race.movethem(c);
                    }
                    catch(Exception e) {}   
            }
    }
    

    class Race {
       int xme, yme, xthem, ythem;
       char me, them;
       char winner;
    
       public Race(char me, int xme, int yme, char them, int xthem, int ythem) { 
          this.me = me;             this.xme = xme;           this.yme = yme;
          this.them = them;       this.xthem = xthem;     this.ythem = ythem;
          winner='?';
          System.out.print("Keys\n I\nJ K\n M\n");
          print();
       }
    
       public void print() {
          for(int y=0; y < 20; y++) {
             for(int x=0; x<20; x++) 
                if (x==xme && y==yme) System.out.print(me); 
                else if (x==xthem && y==ythem) System.out.print(them);
                     else System.out.print('.');
             System.out.println();
          }
          if(over()) System.out.println(winner + " wins");
          System.out.println();
       }
            
       public synchronized void moveme(char direction) {
          switch (direction) {
             case 'I'  : if (yme > 0)  yme--; break;
             case 'J'  : if (xme > 0)  xme--; break;
             case 'K' : if (xme < 19) xme++; break;
             case 'M' : if (yme < 19) yme++; break;
          }
          if(xme == xthem && yme == ythem) { winner = me; them = '*'; me = '*'; }
          print();
        }
    
        public synchronized void movethem(char direction) {
           switch (direction) {
              case 'I' : if (ythem > 0)  ythem--; break;
              case 'J' : if (xthem > 0)  xthem--; break;
              case 'K' : if (xthem < 19) xthem++; break;
              case 'M' : if (ythem < 19) ythem++; break;
           }
           if(xme == xthem && yme == ythem) { winner = them; them = '*'; me = '*';}
           print();
        }
    
        public boolean over() {
           return winner != '?';
        }
    }
    

    Use:

    1. Copy the Racer files from above.
    2. Open two Command Prompt windows.
    3. Compile in one window with:
    4. Execute in different windows by:

    Document last modified: