Documente Academic
Documente Profesional
Documente Cultură
RAPORT
Chisinau 2020
Mersul lucrării:
Server
Primul pas pentru crearea video streaming-ului a fost Serverul, anume el este centrul cu care
comunică fiecare dintre clienții conectați. Serverul și este aplicația ce înregistrează video de pe
desktop, setează video la sine și apoi le transmite clienților. UI al serverului arată astfel:
BufferedImage image;
BufferedImage scaledImage;
@Override
public void run() {
try {
while (running) {
// Get a desktop screenshot
image = getImage();
// Send image
sendMessageToAllClients(getBytes(scaledImage));
image = ImageIO.read(ScreenRecorder.class.getResource("/images/StreamOffline.jpg"));
scaledImage = Scalr.resize(image, Scalr.Method.BALANCED, 480, 270);
jLabelDisplayImages.setIcon(new ImageIcon(scaledImage));
} catch (IOException ex) {
Logger.getLogger(ScreenRecorder.class.getName()).log(Level.SEVERE, null, ex);
}
}
}.start();
}
@Override
public void run() {
while (running) {
try {
waitingBuffer = new byte[256];
processingMessage(packet);
if (!streamStatus) {
startStream();
} else {
stopStream();
}
Dacă clientul dorește să se conecteze la server, acesta este primit de către thread și adăugat
la lista de clienți:
private ArrayList<StreamConnection> streamConnections = new
ArrayList<StreamConnection>();
Clasa StreamConnection răspunde pentru transmiterea sau primirea datelor dintre client-
server; fiecare obiect de tip StreamConnection conține informație despre fiecare dintre clienți.
public class StreamConnection {
private String name;
private InetAddress address;
private int port;
String getName() {
return name;
}
InetAddress getAddress() {
return address;
}
int getPort() {
return port;
}
}
Pentru transmitere se folosește metoda sendMessage, iar pentru transmitere către toți clienții
sendMessageToAllClients:
private byte[] getBytes(String message) {
buffer = new byte[256];
buffer = message.getBytes();
return buffer;
}
Fiecare mesaj este verificat la comandă de către server prin metoda processingMessage(), iar
la adăugarea unui nou client – se verifică dacă este sau nu ocupat numele curent:
Lista comenzilor ce pot fi primite de către server:
message – comandă ce conține un mesaj simplu
connect – comandă de adăugare a unui nou user
disconnect – comandă de ștergere a unui user
// Proccesing message
private void processingMessage(DatagramPacket packet) {
String message = new String(packet.getData());
if (message.startsWith("\\message:")) {
String messageToAdd = message.substring(message.indexOf(":") + 1,
message.indexOf("\\end"));
sendMessageToAllClients(packet.getData());
} else if (message.startsWith("\\connect:")) {
// Get user data
String name = message.substring(message.indexOf(":") + 1, message.indexOf("\\end"));
InetAddress address = packet.getAddress();
int port = packet.getPort();
if (verifyName(name)) {
// Create new user
StreamConnection newUser = new StreamConnection(name, address, port);
// Disconnect user
for (int i = 0; i < streamConnections.size(); i++) {
StreamConnection user = streamConnections.get(i);
if (user.getName().equals(name)) {
streamConnections.remove(i);
break;
}
}
return true;
}
Client
@Override
public void run() {
jLabelStreamStatusMessage.setText("");
String nameless = "Enter your name";
char charAt;
while (streamStatusRunning) {
try {
if (name == null) {
currentMessage = nameless;
jLabelStreamStatusMessage.setForeground(new Color(228, 141, 154));
} else if (streamStatus == false) {
currentMessage = offStream;
jLabelStreamStatusMessage.setForeground(new Color(228, 141, 154));
} else if (streamStatus == true && adminMessages.isEmpty()) {
currentMessage = onStream;
jLabelStreamStatusMessage.setForeground(new Color(0, 255, 51));
} else if (streamStatus == true && !adminMessages.isEmpty()) {
currentMessage = adminMessages.get(0);
adminMessages.remove(0);
jLabelStreamStatusMessage.setForeground(new Color(0, 255, 51));
}
jLabelStreamStatusMessage.setText("");
jLabelStreamStatusMessage.setText(String.valueOf(charAt).concat(jLabelStreamStatusMessage.getText(
)));
Thread.sleep(100);
}
Thread.sleep(3000);
//Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(ClientForm.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}.start();
}
Figura 3. Notificare despre starea stream-ului(online)
if (messageToAdd.startsWith(" Admin")) {
System.out.println(messageToAdd);
adminMessages.add(messageToAdd);
}
} else if (message.startsWith("\\offline")) {
streamStatus = false;
try {
BufferedImage image =
ImageIO.read(StreamClient.class.getResource("/images/StreamOffline.jpg"));
image = Scalr.resize(image, Scalr.Method.BALANCED, 480, 270);
jLabelDisplayImages.setIcon(new ImageIcon(image));
} catch (IOException ex) {
Logger.getLogger(ClientForm.class.getName()).log(Level.SEVERE, null, ex);
}
} else if (message.startsWith("\\busyName")) {
jTextFieldName.setEditable(true);
jLabelDisplayImages.setIcon(new ImageIcon(image));
} catch (IOException ex) {
Logger.getLogger(ClientForm.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
sendMessage("\\disconnect:", name);
}
Întrebări la apărarea laboratorului:
- Ce este un protocol orientat către tranzacții, fără conexiune ?
Este protocolul ce poate transmite și primi pachete fără verificarea datelor. În mare parte
cel ce transmite nu știe dacă au ajuns sau nu datele, el doar le transmite în continuu, la rândul
său cel ce primește nu poate fi sigur că toate datele ajung la el fără pierderi.
- Într-o conexiune UDP, clientul sau serverul trimite mai întâi datele ?
Într-o conexiune UDP, pentru primirea datelor despre client, este nevoie ca clientul să
transmită datele primul, iar serverul deja trebuie să asculte.
- În protocolul UDP este un antet „Total length”, cum se calculează și care este rolul lui ?
Antetul ”Total length” este folosit pentru că UDP transmite mesaje datagram cu o
lungime care poate fi trimis pe mai multe pachete IP fragmentate; plus UDP poate fi transmis
și prin alt protocol decât IP.
Total length = UDP data - UDP header length