{
"title": "Flertrådede servere",
"solutions": "true"
}
| 1 |
Første har vi ClientManager, der modtager alle indkommende forbindelser fra klienterne. |
|
De beskeder der skal sendes mellem brugerne er tilgængelige gennem ClientManager, da det på server-siden er noget der udveksles mellem de enkelte ClientWorkers. Der er derfor lavet metoder hvormed ClientWorker kan gemme og hente beskeder: |
|
import java.net.*;
import java.io.*;
import java.util.ArrayList;
class ClientManager extends Thread {
private ArrayList<ClientWorker> workers;
private int port;
private boolean stop;
public ClientManager( int port ) {
this.port = port;
this.stop = false;
workers = new ArrayList<ClientWorker>();
messages = new ArrayList<Message>();
}
public void run() {
try {
ServerSocket server = new ServerSocket( port, 100 );
server.setSoTimeout( 100 );
System.out.println( "[ClientManager] Server online" );
while ( !stop )
try {
Socket connection = server.accept();
ClientWorker worker = new ClientWorker( this, connection );
workers.add( worker );
worker.start();
}
catch ( SocketTimeoutException e ) {
// ignore timeout
}
server.close();
System.out.println( "[ClientManager] Server offline" );
}
catch ( IOException e ) {
System.out.println( "[ClientManager] I/O error" );
}
}
public void shutdown() {
stop = true;
}
/*
* Messages
*/
private ArrayList<Message> messages;
public void storeMessage( String to, String message ) {
messages.add( new Message( to, message ) );
}
public String getMessage( String userName ) {
for ( Message message : messages )
if ( message.isTo( userName ) ) {
messages.remove( message );
return message.getMessage();
}
return null;
}
}
|
|
Selve Message-klassen er en simpel entitets-klasse. |
|
Bemærk, at oplysningen om hvem beskeden er til, ikke er direkte tilgængelig (information hiding), men kun gennem en konkret forespørgsel om beskeden er til en given bruger: |
|
public class Message {
private String to;
private String message;
public Message( String to, String message ) {
this.to = to;
this.message = message;
}
public boolean isTo( String userName ) {
return to.equalsIgnoreCase( userName );
}
public String getMessage() {
return message;
}
}
|
|
Dernæst har vi ClientWorker, som server-side implementerer protokollen: |
|
import java.net.*;
import java.io.*;
class ClientWorker extends Thread {
private Socket connection;
private ClientManager manager;
private String userName;
public ClientWorker( ClientManager manager, Socket connection ) {
this.manager = manager;
this.connection = connection;
userName = null;
}
public void run() {
System.out.println( "[ClientWorker] New connection from: " +
connection.getInetAddress().getHostAddress() );
try {
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
connection.getOutputStream() ) );
BufferedReader reader = new BufferedReader(
new InputStreamReader(
connection.getInputStream() ) );
while ( true ) {
String line = reader.readLine();
if ( line == null ) // lost connection!
break;
String[] tokens = line.split( " " );
// eller: String[] tokens = line.split( " ", 3 )
// og dernæst bruge tokens[2] for beskeden
String command = tokens[ 0 ].toUpperCase();
System.out.println( "[ClientWorker] Received command: " + command );
if ( command.equals( "LOGIN" ) ) {
userName = tokens[ 1 ];
} else if ( command.equals( "MESSAGE" ) ) {
String to = tokens[ 1 ];
String message = tail( tail( line ) );
manager.storeMessage( to, message );
} else if ( command.equals( "GET" ) ) {
String message = manager.getMessage( userName );
if ( message != null )
sendLine( writer, message );
else
sendLine( writer, "no messages" );
} else if ( command.equals( "LOGOUT" ) )
break;
}
reader.close();
writer.close();
System.out.println( "[ClientWorker] Connection closed" );
}
catch ( IOException e ) {
System.out.println( "[ClientWorker] I/O error" );
}
}
private String tail( String text ) {
int pos = text.indexOf( ' ' );
if ( pos >= 0 )
return text.substring( pos + 1 ).trim();
else
return "";
}
private void sendLine( BufferedWriter writer, String line )
throws IOException
{
System.out.println( "[ClientWorker] sending line: " + line );
writer.write( line );
writer.newLine();
writer.flush();
Sleeper.nap();
}
}
|
|
På klient-siden, har SimpleClient: |
|
import java.net.*;
import java.io.*;
public class SimpleClient extends Thread {
public void run() {
try {
Socket connection = new Socket( "127.0.0.1", 6010 );
System.out.println( "[Client] Connection open" );
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
connection.getOutputStream() ) );
BufferedReader reader = new BufferedReader(
new InputStreamReader(
connection.getInputStream() ) );
sendLine( writer, "LOGIN viggo" );
sendLine( writer, "MESSAGE niels Hej, hvordan går det?" );
// LOGOUT udkommenteret, så vi ikke skal til at lave en ny forbindelse til serveren
//sendLine( writer, "LOGOUT" );
sendLine( writer, "LOGIN niels" );
sendLine( writer, "GET" );
System.out.println( "[Client] " + reader.readLine() );
sendLine( writer, "GET" );
System.out.println( "[Client] " + reader.readLine() );
sendLine( writer, "LOGOUT" );
writer.close();
reader.close();
connection.close();
System.out.println( "[Client] Connection closed" );
}
catch ( IOException e ) {
System.out.println( "[Client] Connection failed" );
}
}
private void sendLine( BufferedWriter writer, String line )
throws IOException
{
System.out.println( "[SimpleClient] sending line: " + line );
writer.write( line );
writer.newLine();
writer.flush();
Sleeper.nap();
}
}
|
|
Og endelig har vi Main, der kører server og klient i hver deres tråd: |
|
public class Main {
public static void main(String[] args) {
ClientManager manager = new ClientManager( 6010 );
manager.start();
Sleeper.nap(); // være sikker på at serveren er online
SimpleClient client = new SimpleClient();
client.start();
Sleeper.sleep( 2.0 );
manager.shutdown();
}
}
[ClientManager] Server online
[Client] Connection open
[SimpleClient] sending line: LOGIN viggo
[ClientWorker] New connection from: 127.0.0.1
[ClientWorker] Received command: LOGIN
[SimpleClient] sending line: MESSAGE niels Hej, hvordan går det?
[ClientWorker] Received command: MESSAGE
[SimpleClient] sending line: LOGIN niels
[ClientWorker] Received command: LOGIN
[SimpleClient] sending line: GET
[ClientWorker] Received command: GET
[ClientWorker] sending line: Hej, hvordan går det?
[Client] Hej, hvordan går det?
[SimpleClient] sending line: GET
[ClientWorker] Received command: GET
[ClientWorker] sending line: no messages
[Client] no messages
[SimpleClient] sending line: LOGOUT
[ClientWorker] Received command: LOGOUT
[ClientWorker] Connection closed
[Client] Connection closed
[ClientManager] Server offline
|