0% found this document useful (0 votes)
4 views

11. networking and multi-threading

The document discusses networking and multi-threading concepts in Java, focusing on the client-server model for a multi-player online game. It explains how clients connect to a server, send and receive messages, and the importance of multi-threading for handling multiple clients concurrently. Additionally, it covers socket connections, TCP ports, and examples of writing both client and server applications in Java.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

11. networking and multi-threading

The document discusses networking and multi-threading concepts in Java, focusing on the client-server model for a multi-player online game. It explains how clients connect to a server, send and receive messages, and the importance of multi-threading for handling multiple clients concurrently. Additionally, it covers socket connections, TCP ports, and examples of writing both client and server applications in Java.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 33

Networking and

Multi-threading
COMP2396 Object-Oriented Programming and Java
Dr. Kenneth Wong
Connecting to Another Program
 Owen would like to extend his fantasy adventure game to a
multi-player online game
 He adopted the client-server model where each player will
launch a client on his own machine that will be connected to
a server over the network
 A client can then communicate with other clients by sending
and receiving messages to and from the server
 In Java, sending and receiving data over the network is just
I/O with a slightly different connection stream
 All the low-level networking details are taken care of by
classes in the java.net package

1
Client-Server Model
 How it works:
Server, I’d like to
1 A client connects to the server connect to the game Waiting for client
requests
Client A
Server

2 The server makes a connection Ok, you’re in Participants:


and adds the client to the list of 1. Client A
participants
Client A
Server

Server, I’d like to


connect to the game Participants:
3 Another client connects
1. Client A
Ok, you’re in 2. Client B
Client B
Server

2
Client-Server Model
 How it works:
“Magician A casts a
4 Client A sends a message to the healing spell” Message
game server received
Client A
Server

“Magician A casts a
healing spell” Message
5 The server distributes the
distributed to all
message to ALL participants
participants
(including the original sender)
Client A
Server

Client B

3
Connecting, Sending, and Receiving
 In order to get his game client working, Owen needs to
learn
1. How to establish the initial connection between the client
and server
2. How to send messages to the server
3. How to receive messages from the server
4. How to send outgoing messages to and simultaneously
receive incoming messages from other participants via
the server

Multi-threading
is the solution!
4
Socket Connection
 Client and server applications communicate over a Socket
connection

 A Socket (java.net.Socket class) is an object that


represents a connection between 2 applications which may
(or may not) be running on 2 different physical machines

 To create a Socket connection, a client must know the IP


address and TCP port number of the server application

Socket socket = new Socket("192.168.1.103", 5000);

IP address for the server TCP port number

5
TCP Port
 A TCP port is a 16-bit unsigned number assigned to a specific
server application
 TCP port numbers allow different clients to connect to the same
machine but communicate with different applications running on
that machine
 TCP port numbers from 0 to 1023 are reserved for well known
services (e.g., 80 for HTTP, 23 for Telnet, 20 for FTP, 25 for SMTP,
and 110 for POP3 mail server, etc.)
 When writing a server program, you might use any TCP port
number between 1024 to 65535
 Only 1 program can be running on a single TCP port. If you try to
bind a program to a port that is already in use, you will get a
java.net.BindException

6
Reading Data from a Socket
 The 4 simple steps in reading data from a socket
1. Make a Socket connection to the server
Socket sock = new Socket("127.0.0.1", 5000); 127.0.0.1 is the IP address
for “localhost” (i.e., the one
2. Make an InputStreamReader this code is running on)
InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());

3. Make a BufferedReader
BufferedReader reader = new BufferedReader(streamReader);

4. Read data
String line = reader.readLine();

destination source
buffered characters converted to characters bytes from server
buffered Data on the
characters 011010011
characters chained to chained to server
Client BufferedReader InputStreamReader Socket’s input stream 7
Server
Writing Data to a Socket
 The 3 simple steps in writing data to a socket
1. Make a Socket connection to the server
Socket sock = new Socket("127.0.0.1", 5000);

2. Make a PrintWriter
PrintWriter writer = new PrintWriter(sock.getOutputStream());

3. Write data println() adds a new line at


writer.println("message to send"); the end of what it sends
writer.print("another message");
print() doesn’t adds the new line

source destination
characters bytes to server
Server
"message..." 011010011
chained to program
Client PrintWriter Socket’s output stream 8
Server
Example: Daily Advice Client
 Example
import java.io.*;
import java.net.*;

public class DailyAdviceClient {


Socket sock;
I/O operations can throw exceptions
public void go() {
try { Make a Socket connection
sock = new Socket("127.0.0.1", 5000);
InputStreamReader streamReader =
new InputStreamReader(sock.getInputStream());
BufferedReader reader = new BufferedReader(streamReader);
String advice = reader.readLine();
System.out.println("Today's advice: " + advice);
reader.close();
} catch (Exception ex) { ex.printStackTrace(); }
}
// code for main()... 9
}
Writing a Simple Server
 How it works: ServerSocket

1 A server application creates a 5000


ServerSocket on a specific port

ServerSocket serverSock = new ServerSocket(5000); Server

2 The server application waits for a new 5000


client

Socket sock = serverSock.accept(); Server

3 A client makes a Socket connection to 5000


the server application
Socket

Socket sock = new Socket("192.168.1.103", 5000); Server

4 The server creates a new Socket to 5000


communicate with this client 5000

Socket sock = serverSock.accept(); Server


Socket 10
Writing a Simple Server
 The accept() method of a ServerSocket blocks (just sits
there) while it is waiting for a client Socket connection

 When a client finally tries to connect, the method returns a


plain Socket on the same port

 This Socket knows how to communicate with the client (i.e.,


it knows the client’s IP address and TCP port number)

11
Example: Daily Advice Server
 Example
import java.io.*;
import java.net.*;

public class DailyAdviceServer {


String[] adviceList = {"Practice makes perfect", "Never give up",
"Focus on the task at hand", "Don't look back", "Be yourself",
"Believe in your own work"};
ServerSocket serverSock;

public String getAdvice() {


int random = (int) (Math.random() * adviceList.length);
return adviceList[random];
}

public static void main(String[] args) {


DailyAdviceServer server = new DailyAdviceServer();
server.go();
} 12
Example: Daily Advice Server
 Example
public void go() {
try {
serverSock = new ServerSocket(5000);

while (true) {
Socket sock = serverSock.accept();
PrintWriter writer = new PrintWriter(sock.getOutputStream());
String advice = getAdvice();
writer.println(advice);
This server application listens for
writer.close();
client requests on port 5000 on the
System.out.println(advice);
machine this code is running on
}
} catch (Exception ex) {
ex.printStackTrace();
}
} // close go
}
The server goes into an infinite loop,
13
waiting for and serving client requests
Multi-threading
 The daily advice server code in the previous example has a
serious limitation that it can only handle 1 client at a time
 It cannot accept a request from another client until it has
finished with the current client and started the next iteration
of the infinite loop
 In order to make the server capable of handling multiple
clients concurrently, separate threads are needed and each
new client Socket should be assigned to a new thread
 Similarly, if a client wants to send and receive messages to
and from the server simultaneously, a separate thread
should be created for receiving messages from the server

14
Multi-threading
 A thread can be considered as a line of execution. It has its
own call stack for storing method invocations and local
variables
 Every application has at least 1 thread running when it is
started (i.e., the main thread)
 The main thread can created additional threads (i.e., worker
threads) to handle different tasks in parallel (e.g., reading
from a file, printing to a printer)
 Multi-threading refers to the ‘concurrent’ execution of
multiple threads in a single application
 Multi-threading often makes an application more responsive
by moving long-running tasks to worker threads

15
Multi-threading in Java
 Java has multi-threading built right into the fabric of the
language
 A Thread (java.lang.Thread class) is an object that
represents a thread of execution
 The 3 simple steps in launching a new thread
1. Make a Runnable object (the thread’s job)
Runnable threadJob = new MyRunnable();
2. Make a Thread object and give it a Runnable (the job)
Thread myThread = new Thread(threadJob);
3. Start the Thread
myThread.start();

16
Runnable Interface
 A Runnable object is to a Thread object what a job is to a
worker. It is an instance of a class that implements the
Runnable interface
 The Runnable interface defines only 1 method
public interface Runnable {
void run();
}

 By passing a Runnable object to the Thread constructor, it


tells the new Thread object which job to run
 When the Thread object’s start() method is called, a new
thread of execution starts and the Runnable object’s run()
method is put on the bottom of the new thread’s stack

17
A Multi-threading Example
 Example
public class MyRunnable implements Runnable {
public void run() { go(); }
public void go() { doMore(); } What will be the output?

public void doMore() { A top of the stack


System.out.println("top of the stack"); back in main
}

public static void main(String[] args) { B back in main


Runnable threadJob = new MyRunnable(); top of the stack
Thread myThread = new Thread(threadJob);
myThread.start();
System.out.println("back in main");
} doMore()
} myThread.start() go()

main() run()

main thread new thread


18
States of a Thread
When the thread is selected
t.start(); by the JVM thread
When the Thread object’s scheduler to run, its call
start() method is called, it stack becomes active and
moves into the runnable the method on the top of
state and a new call stack the stack is executing
is created
selected to run by the JVM
thread scheduler

RUNNABLE
RUNNING

NEW sent back to runnable by the


JVM thread scheduler

Thread t = new Thread(r);


When a Thread object is
created, it is in the new BLOCKED
state and there is no thread When a thread is sleeping, waiting for
of execution yet another thread to finish, waiting for data
to become available on the stream, etc.,
the JVM thread scheduler will move it to
the blocked state 19
Thread Scheduler
 The thread scheduler makes all the decisions about
 Which thread moves from runnable to running state
 When and under what circumstances a thread leaves the
running state
 Where a thread goes when it is kicked out of the running state

 There is no API for calling methods on the scheduler (i.e., no


way to control the scheduler)

 There are no guarantees about scheduling!


 Never base your program’s correctness on the scheduler
working in a particular way!

20
A Multi-threading Example
 Scenario 1:
main()starts the The scheduler The scheduler lets The new thread
new thread sends the main the new thread run goes away because
thread out of to completion, its run() completes.
running and back to printing out The main thread
runnable, so that “top of the stack” once again
the new thread can becoming the
run doMore() running thread, and
prints
myThread.start() myThread.start() go() “back in main”

main() main() run() main()

main thread main thread new thread main thread

time
 Sample output
top of the stack
back in main

21
A Multi-threading Example
 Scenario 2:
main()starts the The scheduler The scheduler lets The scheduler The scheduler The new thread
new thread sends the main the new thread run sends the new selects the main returns to the
thread out of for a little while, not thread back to thread to be the running state and
running and back to long enough for the runnable running thread prints out
runnable, so that run() method to again. main()prints “top of the stack”
the new thread can complete out
run “back in main” doMore()

myThread.start() myThread.start() go() go() go()

main() main() run() run() main() run()

main thread main thread new thread new thread main thread new thread

time
 Sample output
back in main
top of the stack

22
Putting a Thread to Sleep
 One of the best ways to help your threads take turns is to put them
to sleep periodically
Thread.sleep() can
try { throw an exception
Thread.sleep(2000);
} catch (Exception ex) { ex.printStackTrace(); }

 Putting a currently-running thread to sleep will force it to leave the


running state, thus giving another thread a chance to run

 A sleeping thread will not wake up before the specified duration (in
milliseconds)

 When a thread wake up, it always goes back to the runnable state

23
Concurrency Problem
 Concurrency problem may occur when 2 or more threads
have access to the same object on the heap
 Having 2 or more threads accessing the same object at
approximately the same time will result in a race condition,
and may cause data corruption
 Example
 Mr. and Mrs. Smith share a bank account
 They always check the balance before making a withdrawal to
ensure their account will not be overdrawn
 The problem is they always fall asleep in between checking the
balance and making the withdrawal
 When they wake up, they make the withdrawal without
checking the balance again

24
Mr. & Mrs. Smith Example
 Example
public class BankAccount {
private int balance = 100;
public int getBalance() { return balance; }
public void withdraw(int amount) {
balance = balance – amount;
}
}
One single shared
public class SmithJob implements Runnable { bank account
private BankAccount account = new BankAccount();

public static void main(String[] args) {


SmithJob theJob = new SmithJob(); 2 threads having the
Thread mrSmith = new Thread(theJob); same job that accesses
Thread mrsSmith = new Thread(theJob); the same bank account
mrSmith.setName("Mr. Smith");
mrsSmith.setName("Mrs. Smith");
25
Mr. & Mrs. Smith Example
 Example
mrSmith.start();
mrsSmith.start();
} Making a withdrawal
of $60 twice
public void run() {
for (int x = 0; x < 2; x++) {
makeWithdrawal(60);
}
}
Checking the balance
private void makeWithdrawal(int amount) { before withdrawal
if (account.getBalance() >= amount) {
System.out.println(getName() + " is about to withdraw");
try {
System.out.println(getName() + " is going to sleep");
Thread.sleep(500); Falling asleep
} catch (Exception ex) { ex.printStackTrace(); }
26
Mr. & Mrs. Smith Example
 Example Waking up and
completing the
System.out.println(getName() + " wakes up"); withdrawal
account.withdraw(amount);
System.out.println(getName() + " completes the withdrawal");
if (account.getBalance() < 0) {
System.out.println("Overdrawn!"); Checking for overdrawn
}
}
else {
System.out.println("Not enough money for " + getName());
}
}

private String getName() {


return Thread.currentThread().getName();
}
}

27
Mr. & Mrs. Smith Example
 Sample output
Mr. Smith is about to withdraw
Mr. Smith is going to sleep
Mrs. Smith is about to withdraw
Mrs. Smith is going to sleep
Mr. Smith wakes up
Mrs. Smith wakes up
Mr. Smith completes the withdrawal
Mrs. Smith completes the withdrawal
Overdrawn!
Overdrawn!
Not enough money for Mr. Smith
Not enough money for Mrs. Smith

28
Synchronization
 To solve the concurrency problem in the previous example, we
need to make sure that once a thread has checked the account
balance, it has a guarantee that it can wake up and finish the
withdrawal before any other thread can check the account balance
 This can be achieved by making the makeWithdrawal() method
atomic
 Use the keyword synchronized to modify a method so that only 1
thread at a time can access it
private synchronized void makeWithdrawal(int amount) {
// ...
}
 To protect your data (like the bank account), synchronize the
methods that act on that data

29
Using an Object’s Lock
 Every Java object has a lock with a single key
 Most of time, the lock is unlocked
 Object locks come into play only when
there are synchronized methods
 A thread can enter one of the synchronized
methods only if it can get hold of the object’s key
 Even if an object has more than 1 synchronized method, there is
still only 1 key
 Once a thread has entered a synchronized method on an object,
no other threads can enter any synchronized methods on the
same object

30
Deadlock Problem
 A thread deadlock happens when you have two
threads, both of which are holding a key the other
thread wants
1 Thread A enters a synchronized 3 Thread B enters a synchronized 5 Thread A wakes up (still holding
method on object foo, and gets method on object bar, and gets the foo key) and tries to enter a
the key. the key. synchronized method on object
bar, but can’t get that key
because B has it. A goes to the
waiting lounge, and waits until
the bar key becomes available.
2 Thread A goes to sleep, holding
the foo key. 4 Thread B tries to enter a
synchronized method on object
foo, but can’t get that key
because A has it. B goes to the
waiting lounge, and waits until 6 Thread A can’t run until it can
the foo key becomes available. get the bar key, but B is holding
B keeps the bar key. the bar key, and B can’t run
until it gets the foo key that A is
holding and …

31
Deadlock Problem
 There is no way out of this scenario and the two
threads will simply sit and wait forever!

 Java has no mechanism to handle deadlock, and it


won’t even know a deadlock occurred

 It is up to you to design carefully!

32

You might also like