Это мой студенческий проект. Я получил 4/5 баллов, но подозреваю, что там много странностей. У меня никогда не было возможности услышать отзыв своего учителя об этом, и это меня беспокоит, поэтому я подумал, что кто-то может взглянуть на него и дать отзыв.
Быстрая документация
Сначала мы запускаем программу «Сервер», которая открывает порты, предоставленные аргументами среды выполнения.[] параметры прослушивания параллельно в отдельных потоках.
Затем мы запускаем «Клиент», передавая имя хоста конструктора и список портов, которые нужно сбить. Мы можем запустить много клиентов или установить переменную numberofclients в коде.Серверные UDP-сокеты имеют доступ к синхронизированной структуре данных, в которой хранится информация о входящих соединениях с сокетами.
После каждого подключения программа проверяет, соответствует ли порядок подключений ключевому. Если да затем сервер отправляет сообщение с TCP-портом в сокет неавторизованного, но все же клиента, который отправил правильную комбинацию портов, и другой поток запускается с TCP-сокетом, который прослушивает авторизованного клиента. Авторизованный клиент подключается к TCP-сокету и обменивается короткой информацией с сервером. После обмена TCP сокет закрывается.Клавиша Enter закрывает программу, и все потоки и сокеты освобождаются.
Сервер
package com.company;
import java.io.IOException;
import java.net.*;
import java.util.*;
import java.util.stream.Collectors;
public class Server implements Runnable{
byte[] buffer = new byte[2048];
byte[] sendBuffer = new byte[2048];
List<DatagramSocket> socketList;
Map<InetSocketAddress, List<Integer>> internalMap;
Map<InetSocketAddress, List<Integer>> guestMap;
List<Integer> key;
Server(Integer... ports) throws SocketException {
this.key = new ArrayList<>();
//key.addAll(Arrays.asList(ports));
for(Integer portnumber : ports)
key.add(portnumber);
this.socketList = new ArrayList<>();
this.internalMap = new HashMap<>();
this.guestMap = Collections.synchronizedMap(internalMap);
List<Integer> uniquePorts = key.stream().distinct().collect(Collectors.toList());
for(Integer port: uniquePorts){
DatagramSocket socket = new DatagramSocket(port);
socketList.add(socket);
}
System.out.println("Zajete porty: ");
socketList.forEach(n -> System.out.print(n.getLocalPort() + ", "));
System.out.println();
this.key = socketList.stream().map(DatagramSocket::getLocalPort).collect(Collectors.toList());
}
@Override
public void run() {
for(DatagramSocket socket : socketList){
Thread t = new Thread(){
boolean running;
@Override
public void run() {
while(true){
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try {
socket.receive(packet);
ProtocolMessage msgRecvd = new ProtocolMessage(packet.getData());
System.out.println(msgRecvd); //dbgging
if(!msgRecvd.equals(Protocol.synMessage))
throw new ProtocolException("Request not recognized, possibly malformed");
InetAddress address = packet.getAddress();
int port = packet.getPort();
InetSocketAddress guest = new InetSocketAddress(address,port);
if(guestMap.containsKey(guest)){
guestMap.get(guest).add(socket.getLocalPort()); //refactor it later
if(guestMap.get(guest).equals(key)){
ServerClientService serverClientService = new ServerClientService();
int establishedPort = serverClientService.serverSocket.getLocalPort();
System.out.println("Guest: " + address + ":" + port+ " authenticated sending tcp port: " + establishedPort);
ProtocolMessage auth = Protocol.authSuccess;
auth.setValue(establishedPort);
sendBuffer = auth.toByte();
socket.send(new DatagramPacket(sendBuffer,sendBuffer.length, address, port));
serverClientService.run();
}
else if(key.size() < guestMap.get(guest).size()){
guestMap.remove(guest);
}
}
else{
List<Integer> list = new ArrayList<>();
List<Integer> synchlist = Collections.synchronizedList(list);
synchlist.add(socket.getLocalPort());
guestMap.put(guest, synchlist);
}
sendBuffer = Protocol.ackMessage.toByte();
DatagramPacket confirmation = new DatagramPacket(sendBuffer, sendBuffer.length, address, port);
socket.send(confirmation);
}catch (SocketTimeoutException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
t.setDaemon(true); //inne wątki nie moga istniec bez procesu main
t.start();
}
Scanner s = new Scanner(System.in);
System.out.println("Naciśnij "Enter" aby wyjść.....");
s.nextLine();
}
}
Служба TCP сервер-клиент
package com.company;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerClientService implements Runnable {
ServerSocket serverSocket;
ServerClientService(){
try {
serverSocket = new ServerSocket(0);
} catch (IOException e) {
e.printStackTrace();
System.err.println("Port niedostepny");
}
}
@Override
public void run() {
try( Socket clientSocket = serverSocket.accept();
PrintWriter out = new PrintWriter(clientSocket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))
)
{
String query = in.readLine();
System.out.println(query);
String response = "hello there client " + getPort();
out.println(response);
out.flush();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public int getPort() {
return serverSocket.getLocalPort();
}
}
Клиент
package com.company;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
public class Client {
byte[] sendBuffer;
byte[] recvBuffer;
DatagramSocket socket;
String hostName;
List<Integer> key;
Client(String address, int... ports) throws SocketException {
this.key = new ArrayList<>();
this.sendBuffer = new byte[2048];
this.recvBuffer = new byte[2048];
this.socket = new DatagramSocket();
this.hostName = address;
for(int i : ports)
this.key.add(i);
}
public void run() {
try {
InetAddress inetAddress = InetAddress.getByName(hostName);
for(Integer port : key){
sendBuffer = Protocol.synMessage.toByte();
DatagramPacket packet = new DatagramPacket(sendBuffer, sendBuffer.length, inetAddress,port);
socket.send(packet);
//System.out.println("sent: " + new ProtocolMessage(sendBuffer));
DatagramPacket returnPacket = new DatagramPacket(recvBuffer, recvBuffer.length);
returnPacket.setLength(returnPacket.getLength());
socket.setSoTimeout(5000);
try {
socket.receive(returnPacket);
} catch (SocketTimeoutException e){
System.err.println("No response, probably invalid authentication");
}
ProtocolMessage response = new ProtocolMessage(returnPacket.getData());
System.out.println(response); //debugging
if (response.equals(Protocol.ackMessage)) {
//proceed
continue;
}
else if(response.equals(Protocol.authSuccess)){
//connect to sent tcp port
int portNumber = response.value;
startTcpConnection(portNumber);
break;
}
else{
throw new ProtocolException("Response not recognized, possibly malformed");
//should like catch it and try again perhaps
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
socket.close();
}
public void startTcpConnection(int port ){
try(Socket tcpSocket = new Socket(hostName, port);
PrintWriter out = new PrintWriter(tcpSocket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(tcpSocket.getInputStream()));)
{
out.println("Client " + port + ": hello");
out.flush();
String response = in.readLine();
System.out.println(response);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Общий протокол
package com.company;
public class Protocol {
final static ProtocolMessage synMessage = new ProtocolMessage(1);
final static ProtocolMessage ackMessage = new ProtocolMessage(2);
final static ProtocolMessage authSuccess = new ProtocolMessage(3);
}
package com.company;
import java.nio.ByteBuffer;
public class ProtocolMessage {
int type;
int value;
ProtocolMessage(int type, int value){
this.type = type;
this.value = value;
}
ProtocolMessage(int type){
this.type = type;
this.value = 0;
}
ProtocolMessage(byte[] bytes){
ByteBuffer wrapped = ByteBuffer.wrap(bytes);
this.type = wrapped.getInt(0);
this.value = wrapped.getInt(50);
}
public byte[] toByte(){
ByteBuffer byteBuffer = ByteBuffer.allocate(2048);
byteBuffer.putInt(0,this.type);
byteBuffer.putInt(50,this.value);
return byteBuffer.array();
}
@Override
public String toString(){
return type + ":" + value;
}
@Override
public boolean equals(Object o){
ProtocolMessage another = (ProtocolMessage) o;
if(another.type == this.type)
return true;
else
return false;
}
void setValue(int value){
this.value = value;
}
}
