Цель работы. Познакомиться с техникой использования сокетных классов Java.
Краткое теоретическое содержание. В разрабатываемом ниже приложении «клиент-сервер» используются два параллельно выполняющихся потока: поток-сервер и поток-клиент.
Для установления связи между клиентом и сервером нужно создать сокетное соединение как на серверной, так и на клиентской стороне. На стороне клиента это делается так
class clientThread extends Thread{
DataInputStream stream=null;
Socket socket=null;
public clientThread()
{ try{
socket=new Socket("127.0.0.1",3001);
... и т.д.
Здесь объявлена переменная типа Socket, которая создается в команде
socket=new Socket("127.0.0.1",3001);
Подключение клиента к серверу:
socket=server.accept();
В данной лабораторной работе серверпередает клиенту данные о банковском счете, представленные случайными целыми числами. На стороне сервера это делается таким образом
class Account extends Thread{
private ServerSocket server;
private int amount;
Account(int amount) throws IOException{
this.server = new ServerSocket(3001);
this.amount = amount;
}
@Override
public void run(){
//#account cycle#
while(true){
//create output stream
//it will be wired with socket
//server.accept() returns socket
try (PrintStream ps = new PrintStream(server.accept().getOutputStream())) {
//generate amount
int amountcur=((int)(Math.random()*1000));
//generate sign
if(Math.random() > 0.5) {
amountcur*=(-1);
}
//count
amount += amountcur;
//print results to account output stream
ps.println("Action: " + amountcur);
ps.println("Account result: " + amount);
ps.flush();
}catch(IOException ex){
System.out.println("Exception: " + ex);
}
}
Поток вывода для сервера реализуется через переменную ps:
PrintStream
ps=new PrintStream(s.getOutputStream());
Объектная переменная ps предоставляет методы вывода, например
ps.println("Account:"+amountcur);
В команде
amountcur=((int)(Math.random()*1000));
на счет клиента добавляется случайная величина с помощью метода
random, генерирующего случайные числа от 0 до 1.
|
Изменение суммы в переменной amount выполняется путем внесения или снятия случайной величины со счета:
int amountcur=((int)(Math.random()*1000));
if (Math.random()>0.5)
amount*=(-1);
}
amount+=amountcur;
Серверная часть реализована как приложение Java на основе формы c главным методом main:
public static void main(String args[])
{
serv f=new serv();
f.resize(400,400);
f.show();
new Account().start();
}
Базовым классом сервера является класс serv.
Главный метод запускает поток-сервера
new Account().start();
Базовый класс приложения реализует обработку события закрытия окна:
@Override
public boolean handleEvent(Event evt)
{
if (evt.id==Event.WINDOW_DESTROY)
{System.exit(0);}
return super.handleEvent(evt);
}
Тип событияпроверяется командой
if (evt.id==Event.WINDOW_DESTROY)
Второй метод
@Override
public boolean mouseDown(Event evt,int x,int y)
{
new clientThread().start();
return(true);
}
обрабатывает щелчок мышью в окне сервера (по щелчку в окне запускается клиент):
new clientThread().start();
И сервер, и клиент реализованы как отдельные потоки. Поток клиента такой
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
class clientThread extends Thread{
DataInputStream stream=null;
Socket socket=null;
public clientThread()
{ try{
socket = new Socket("127.0.0.1", 3001);
System.out.println("Socket " + socket);
//erlier it was created in account
//if not, wait for null pointer;(
stream = new DataInputStream(socket.getInputStream());
System.out.println("Stream " + stream); }
catch(Exception e)
{ System.out.println("Ошибка: "+e);
}}
public void run(){
System.out.println("Start getting messages from server");
String msg;
//While there are any messages in input stream from server
//Client will print this messages
try {
while((msg = stream.readLine())!= null){
sleep(100);
System.out.println(msg);
}
} catch (IOException ex) {
System.out.println("Exception " + ex);
} catch (InterruptedException ex) {
System.out.println("Problems with sleepping, it's srange " + ex);
|
}
System.out.println("The End");
}
}
Клиент инициализируется таким образом
DataInputStream stream = null;
Socket socket = null;
public ClientThread()
{
try
{
socket = new Socket("127.0.0.1", 3001);
System.out.println("Socket " + socket);
//erlier it was created in account
//if not, wait for null pointer;(
stream = new DataInputStream(socket.getInputStream());
System.out.println("Stream " + stream);
}
Итог:
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
class Account extends Thread{
private ServerSocket server;
private int amount;
Account(int amount) throws IOException{
this.server = new ServerSocket(3001);
this.amount = amount;
}
@Override
public void run(){
while(true){
try (PrintStream ps = new PrintStream(server.accept().getOutputStream())) {
//generate amount
int amountcur=((int)(Math.random()*1000));
//generate sign
if(Math.random() > 0.5) {
amountcur*=(-1);
}
//count
amount += amountcur;
//print results to account output stream
ps.println("Action: " + amountcur);
ps.println("Account result: " + amount);
ps.flush();
}catch(IOException ex){
System.out.println("Exception: " + ex);
}
}
}
}
class ClientThread extends Thread
{
DataInputStream stream = null;
Socket socket = null;
public ClientThread()
{
try
{
socket = new Socket("127.0.0.1", 3001);
System.out.println("Socket " + socket);
//erlier it was created in account
//if not, wait for null pointer;(
stream = new DataInputStream(socket.getInputStream());
System.out.println("Stream " + stream);
}
catch(Exception e)
{
System.out.println("Ошибка " + e);
}
}
public void run(){
System.out.println("Start getting messages from server");
String msg;
//While there are any messages in input stream from server
//Client will print this messages
try {
while((msg = stream.readLine())!= null){
sleep(100);
System.out.println(msg);
}
} catch (IOException ex) {
System.out.println("Exception " + ex);
} catch (InterruptedException ex) {
System.out.println("Problems with sleepping, it's srange " + ex);
}
System.out.println("The End");
}
}
public class Serv extends Frame
{
@Override
public boolean handleEvent(Event evt){
if(evt.id==Event.WINDOW_DESTROY){
System.exit(0);
|
}
return super.handleEvent(evt);
}
@Override
public boolean mouseDown(Event evt,int x,int y){
//when mouse clicked, client thread prints one iteration #account cycle# from account class
new ClientThread().start();
return(true);
}
}
public class Lab_2 {
public static void main(String[] args) throws IOException
{
Account account = new Account(1000);
account.start();
Serv f= new Serv();
f.resize(400,400);
f.show();
}
}
Задание
1. Завершите приложение работоспособной программой, в которой используются описанные поток сервера и поток клиента.
2. Создайте свой вариант программы на основании следующих данных.
2.1. Написать приложение для двух клиентов, которые работают с одним счетом. Каждому клиенту соответствует свой поток.
2.2. Cоздать приложение клиент-сервер с некоторым визуальным интерфейсом, который выполняет запуск клиента по нажатию кнопки и отражает состояние счета в текстовом поле.
Контрольные вопросы.
1. Объясните назначение протоколов TCP, UDP. В чем их отличие?
2. С помощью каких объектов и каких методов данные отсылаются по сети?
3. Как реализовать пересылку данных в обратном направлении (от клиента к серверу)?
4. Как определить сетевой адрес вашего компьютера.