Java:Tutorials:Simple TCP Networking

From GPWiki
Jump to: navigation, search

TCP Networking

TCP networking in Java is accomplished by using the Socket and ServerSocket classes. For a Java network to be set up there must be a server and a client program running. The sample Client and Server classes shown below is a simple example showing how to send two int-values from the client to the server preforming a computation on the numbers within the server program and then sending it back to the client program.

The Client

The Client in this sample program has four main sections.

  1. Create a Socket, PrintWriter, and BufferedReader and connect to Server.
  2. Get and send the two numbers (from user) to the Client.
  3. Recieve the answer from the Cient.
  4. Close Socket, PrintWriter, and BufferedReader.
import java.io.*;
import java.net.*;
 
public class client {
    public static void main(String[] args) throws IOException {
 
        Socket socket = null;
        PrintWriter out = null;
        BufferedReader in = null;
 
        try {
            socket = new Socket("127.0.0.1", 1234);
            out = new PrintWriter(socket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host");
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection");
            System.exit(1);
        }
 
        BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
        String num1,num2;
 
		//System.out.println(in.readLine()); //Uncomment to debug
 
		System.out.print("This int-->");
		num1=read.readLine();
		out.println(num1);
		System.out.print("Times this int-->");
		num2=read.readLine();	
		out.println(num2);
		System.out.println("Equals");
 
		System.out.println(in.readLine());
 
        out.close();
        in.close();
        read.close();
        socket.close();
    }
}

1.

        Socket socket = null;
        PrintWriter out = null;
        BufferedReader in = null;

These 3 lines declare the Socket, PrintWriter, and BufferedReader

        try {
            socket = new Socket("127.0.0.1", 1234);
            out = new PrintWriter(socket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host");
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection");
            System.exit(1);
        }

We enclose the next set commands, displayed above, in a try method in case an error occurs. new Socket(IP or name of Machine, port); The "127.0.0.1" IP address is a loop back address so you can connect to the server program on the same computer. The port numbers need to be the same between the programs. The "out" PrintWriter is used to send strings to the server program, and the "in" BufferedReader is used to recieve strings from the client program. The catch methods catch errors and exceptions (if any) then exits the program.


2.

        BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
        String num1,num2;

Declares 'read' which enables the client to get data from the user. 'num1' and 'num2' are strings which hold the int numbers to be calculated.

 
		//System.out.println(in.readLine()); //Uncomment to debug
 
		System.out.print("This int-->");
		num1=read.readLine();
		out.println(num1);
		System.out.print("Times this int-->");
		num2=read.readLine();	
		out.println(num2);

The 'out.println(num1);' and 'out.println(num2);' commands send the strings to the server program.


3.

                System.out.println(in.readLine());

This line will get, from client, the calculated number.


4.

        out.close();
        in.close();
        read.close();
        socket.close();

The statements here simply clean up when finished.

The Server

For this example the server should be run first.

import java.net.*;
import java.io.*;
 
public class server {
    public static void main(String[] args) throws IOException {
 
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(1234);
        } catch (IOException e) {
            System.err.println("Could not listen on port: 1234.");
            System.exit(1);
        }
 
        Socket clientSocket = null;
        try {
            clientSocket = serverSocket.accept();
        } catch (IOException e) {
            System.err.println("Accept failed.");
            System.exit(1);
        }
 
        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        String int1,int2;
	int num1=0,num2=0;
 
	//out.println("server: Connected");//uncomment for debug
 
 
 
	int1 = in.readLine();
	System.out.println(int1);
	int2 = in.readLine();
	System.out.println("*"+int2);
 
 
	try
	{  
        num1=Integer.parseInt(int1);
        num2=Integer.parseInt(int2);
        }
        catch(NumberFormatException nfe)
        {
        	System.out.println("Numbers not intergers");
        	out.println("Numbers not intergers");
        }
        System.out.println("="+num1*num2);
        out.println(String.valueOf(num1*num2));
 
 
 
        out.close();
        in.close();
        clientSocket.close();
        serverSocket.close();
    }
}

For the server the ServerSocket class will be used. Which has only the parameter for the port, no IP address is needed.

        Socket clientSocket = null;
        try {
            clientSocket = serverSocket.accept();
        } catch (IOException e) {
            System.err.println("Accept failed.");
            System.exit(1);
        }

The code above creates a Socket to store the socket from the client machine. The serverSocket uses the accept() method to wait for a connection from a client. Then we declare our 'in' 'out' and other variables.

	int1 = in.readLine();
	System.out.println(int1);
	int2 = in.readLine();
	System.out.println("*"+int2);

These four lines get the first and second strings which stores our ints from the client program

	try
	{  
        num1=Integer.parseInt(int1);
        num2=Integer.parseInt(int2);
        }
        catch(NumberFormatException nfe)
        {
        	System.out.println("Numbers not intergers");
        	out.println("Numbers not intergers");
        }
        System.out.println("="+num1*num2);
        out.println(String.valueOf(num1*num2));

This code segment will turn our strings to actuals ints. Multiply them and send the total back to the client program.

Use these programs for convient computer to computer testing

example

//package com.hypefiend.javagamebook.chatterbox;
 
import java.nio.*;
import java.nio.charset.*;
import java.nio.channels.*;
import java.util.*;
import java.net.*;
import java.io.*;
import TerminalIO.*;
/**
 * ChatterClient.java
 *
 * A basic example of a multi-user chat application using the JDK 1.4 NIO libraries
 * 
 * @author <a href="mailto:bret@hypefiend.com">bret barker</a>
 * @version 1.0
 */
public class ChatterClient extends Thread {
    private static final int BUFFER_SIZE = 255;
    private static final long CHANNEL_WRITE_SLEEP = 10L;
    private static final int PORT = 10997;
 
    private ByteBuffer writeBuffer;
    private ByteBuffer readBuffer;
    private boolean running;
    private SocketChannel channel;
    private String host;
    private Selector readSelector;
    private CharsetDecoder asciiDecoder;
    private InputThread it;
 
    public static void main(String args[]) {
	String host; 
	KeyboardReader read=new KeyboardReader();
	host = read.readLine("Host Address -> ");
	ChatterClient cc = new ChatterClient(host);
	cc.start();
    }
 
    public ChatterClient(String host) {
 
	this.host=host;
 
	writeBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
	readBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
	asciiDecoder = Charset.forName( "US-ASCII").newDecoder();;
    }
 
    public void run() {
	connect(host);
	it = new InputThread(this);
	it.start();
 
	running = true;
	while (running) {
	    readIncomingMessages();
 
	    // nap for a bit
	    try {
		Thread.sleep(50);
	    }
	    catch (InterruptedException ie) {
	    }
	}
    }
 
    private void connect(String hostname) {
	try {
	    readSelector = Selector.open();
	    InetAddress addr = InetAddress.getByName(hostname);
	    channel = SocketChannel.open(new InetSocketAddress(addr, PORT));
	    channel.configureBlocking(false);
	    channel.register(readSelector, SelectionKey.OP_READ, new StringBuffer());
	}
	catch (UnknownHostException uhe) {
	}
	catch (ConnectException ce) {
	}
	catch (Exception e) {
	}
    }
 
    private void readIncomingMessages() {
	// check for incoming mesgs
	try {
	    // non-blocking select, returns immediately regardless of how many keys are ready
	    readSelector.selectNow();
 
	    // fetch the keys
	    Set readyKeys = readSelector.selectedKeys();
 
	    // run through the keys and process
	    Iterator i = readyKeys.iterator();
	    while (i.hasNext()) {
		SelectionKey key = (SelectionKey) i.next();
		i.remove();
		SocketChannel channel = (SocketChannel) key.channel();
		readBuffer.clear();
 
		// read from the channel into our buffer
		long nbytes = channel.read(readBuffer);
 
		// check for end-of-stream
		if (nbytes == -1) { 
		    System.out.println("disconnected from server: end-of-stream");
		    channel.close();
		    shutdown();
		    it.shutdown();
		}
		else {
		    // grab the StringBuffer we stored as the attachment
		    StringBuffer sb = (StringBuffer)key.attachment();
 
		    // use a CharsetDecoder to turn those bytes into a string
		    // and append to our StringBuffer
		    readBuffer.flip( );
		    String str = asciiDecoder.decode( readBuffer).toString( );
		    sb.append( str );
		    readBuffer.clear( );
 
		    // check for a full line and write to STDOUT
		    String line = sb.toString();
		    if ((line.indexOf("\n") != -1) || (line.indexOf("\r") != -1)) {
			sb.delete(0,sb.length());
			System.out.print("\n" + line);
			System.out.print("> ");
		    }
		}
	    }		
	}
	catch (IOException ioe) {
	}
	catch (Exception e) {
	}
    }
 
    private void sendMessage(String mesg) {
	prepWriteBuffer(mesg);
	channelWrite(channel, writeBuffer);
    }
 
    private void prepWriteBuffer(String mesg) {
	// fills the buffer from the given string
	// and prepares it for a channel write
	writeBuffer.clear();
	writeBuffer.put(mesg.getBytes());
	writeBuffer.putChar('\n');
	writeBuffer.flip();
    }
 
    private void channelWrite(SocketChannel channel, ByteBuffer writeBuffer) {
	long nbytes = 0;
	long toWrite = writeBuffer.remaining();
 
	// loop on the channel.write() call since it will not necessarily
	// write all bytes in one shot
	try {
	    while (nbytes != toWrite) {
		nbytes += channel.write(writeBuffer);
 
		try {
		    Thread.sleep(CHANNEL_WRITE_SLEEP);
		}
		catch (InterruptedException e) {}
	    }
	}
	catch (ClosedChannelException cce) {
	}
	catch (Exception e) {
	} 
 
	// get ready for another write if needed
	writeBuffer.rewind();
    }
 
    public void shutdown() {
	running = false;
	interrupt();
    }
 
    /** 
     * InputThread reads user input from STDIN
     */
    class InputThread extends Thread {
	private ChatterClient cc;
	private boolean running;
	public InputThread(ChatterClient cc) {
	    this.cc = cc;
	}
 
	public void run() {
	    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	    running = true;
	    while (running) {
		try {
		    String s;
		    System.out.print("> ");
		    System.out.flush();
		    s = br.readLine();
		    if (s.length() > 0)
			cc.sendMessage(s + "\n");
		    if (s.equals("quit")) 
			running = false;
		}
		catch (IOException ioe) {
		    running = false;
		}
	    }
	    cc.shutdown();
	}
	public void shutdown() {
	    running = false;
	    interrupt();
	}
    }
}