import
java.io.*;
import
java.net.*;
import
java.util.*;
public
class
StockQuoteServer
{
private
static
final
int
SERVER_PORT=1701;
//порт, который будет прослушиваться сервером
private
static
final
int
MAX_CLIENTS=50;
//максимальное количество подключенных клиентов
private
static
final
File STOCK_QUOTES_FILE=new
File("stockquotes.txt");
//файл с данными
private
ServerSocket listenSocket;
//сокет
private
String[]
stockInfo;
private
Date stockInfoTime;
private
long
stockFileMode;
private
boolean
keepRunning=true;
//флаг, сброс которого приводит к завершению работы
сервера
//запуск приложения
public
static
void
main(String
args[])
{
StockQuoteServer server
=
new
StockQuoteServer();
server.serverQuotes();
}
//Конструктор загружает данные об акциях, после чего
сервер
//ожидает запросы от клиентов
public
StockQuoteServer()
{
if(!loadQuotes())
System.exit(1);
//загружает данные, если ошибка - завершает работу
try
{
listenSocket=new
ServerSocket(SERVER_PORT,
MAX_CLIENTS);
//создать сокет
}
catch(IOException
except)
{
System.err.println("Unable
to listen on port "+SERVER_PORT);
System.exit(1);
}
}
//загрузка данных из файла
protected
boolean
loadQuotes()
{
String fileLine;
StringBuffer inputBuffer=new
StringBuffer();
int
numSocks=0;
try
{
//создать поток для чтения данных из файла
DataInputStream stockInput=new
DataInputStream(new
FileInputStream(STOCK_QUOTES_FILE));
//считаем каждую строку
while((fileLine=stockInput.readLine())!=null)
{
inputBuffer.append(fileLine.toUpperCase()+"\n");
//поместить строку в буфер
numSocks++;
//увеличить счетчик
}
stockInput.close();
//сохранить время последней модификации
stockFileMode=STOCK_QUOTES_FILE.lastModified();
}
catch(FileNotFoundException
except)
{
System.err.println("Unable
to find file: "+except);
return
false;
}
catch
(IOException
except)
{
System.err.println("I/O
exception: "+except);
return
false;
}
stockInfo=new
String[numSocks];
//создадим массив строк для чтения инфы из файла
String inputString=inputBuffer.toString();
//указатели для создания подстрок
int
stringStart=0;
//начало строки
int
stringEnd=0;
//конец строки
for(int
index=0;
index<numSocks;
index++)
{
stringEnd=inputString.indexOf("\n",stringStart);
//если \n больше не встречается, то весь остаток
inputString
if(stringEnd==-1)
{
stockInfo[index]=inputString.substring(stringStart);
}
else
{
stockInfo[index]=inputString.substring(stringStart,
stringEnd);
}
stringStart=stringEnd+1;
//передвинем указатель на следующую строку
}
stockInfoTime=new
Date();
//сохраним время загрузки
return
true;
}
//Этот метод ожидает обращение от клиента
public
void
serverQuotes()
{
Socket clientSocket=null;
try
{
while(keepRunning)
{
clientSocket=listenSocket.accept();
//присоединить нового клиента
//Если файл данных изменен, загрузить данные повторно
if(stockFileMode!=STOCK_QUOTES_FILE.lastModified())
{
loadQuotes();
}
//Создать новый обработчик
StockQuoteHandler newHandler
=
new
StockQuoteHandler(clientSocket,
stockInfo,
stockInfoTime);
Thread newHandlerThread=new
Thread(newHandler);
newHandlerThread.start();
}
listenSocket.close();
}
catch(IOException
e)
{
System.err.println("Failed
I/O "+e);
}
}
//метод для остановки сервера
protected
void
stp()
{
if(keepRunning)
{
keepRunning=false;
}
}
}
//Класс для обеспечения связи с отдельным клиентом
class
StockQuoteHandler
implements
Runnable
{
private
Socket mySocket=null;
private
PrintStream clientSend=null;
private
DataInputStream clientReceive=null;
private
String[]
stockInfo;
private
Date stockInfoTime;
//конструктор
public
StockQuoteHandler(Socket
newSocket,
String[]
info,
Date time)
{
mySocket=newSocket;
stockInfo=info;
stockInfoTime=time;
}
//поток, релизующий обмен данными
public
void
run()
{
String nextLine;
String quoteID;
String quoteResponse;
try
{
clientSend=new
PrintStream(mySocket.getOutputStream());
clientReceive=new
DataInputStream(mySocket.getInputStream());
clientSend.println("+HELLO
"+stockInfoTime);
clientSend.flush();
//получить строку от клиента и ответить
while((nextLine=clientReceive.readLine())!=null)
{
nextLine=nextLine.toUpperCase();
//команды выхода
if(nextLine.indexOf("QUIT")==0)
break;
//команда STOCK
else
if(nextLine.indexOf("STOCK:
")==0)
{
quoteID=nextLine.substring("STOCK:
".length());
quoteResponse=getQuote(quoteID);
clientSend.println(quoteResponse);
clientSend.flush();
}
//неизвестная команда
else
{
clientSend.println("-ERR
UNKNOWN COMMAND");
clientSend.flush();
}
}
clientSend.println("+BUY");
clientSend.flush();
}
catch(IOException
e)
{
System.err.println("Failed
I/O "+e);
}
finally
{
//закроем потоки и сокет
try
{
if(clientSend!=null)
clientSend.close();
if(clientReceive!=null)
clientReceive.close();
if(mySocket!=null)
mySocket.close();
}
catch(IOException
e)
{
System.err.println("Failed
I/O "+e);
}
}
}
//Получить информацию по заданному идентификатору
protected
String getQuote(String
quoteID)
{
for(int
index=0;
index<stockInfo.length;
index++)
{
if(stockInfo[index].indexOf(quoteID)==0)
return
"+"+stockInfo[index];
}
return
"-ERR UNKNOWN STOCK ID";
}
} |