Sunteți pe pagina 1din 10

Ministerul Educației, Culturii și Cercetării

Universitatea Tehnică a Moldovei


Facultatea Calculatoare, Informatică și Microelectronică
Departamentul Ingineria Software și Automatică

Raport
Lucrarea de laborator nr.5
Disciplina: Programarea în Rețea
Tema: Aplicații client-server: Sockets API

Efectuat: st.gr.TI-161 Leahu Ion


st.gr.TI-161 Glavan Gheorghe
st.gr.TI-161 Topală Mihai
Verificat: Zgureanu Aureliu

Chișinău 2020
Scopul lucrării:
Studierea Sockets API. Operații tip pentru conexiuni prin socket pentru
client. Operații tip pentru conexiuni prin socket pentru server.

Obiectivele lucrării:
Realizarea unui chat cu posibilitatea conectării mai multor clienți simultan

Note teoretice:
Modelul client-server este o structură sau arhitectură aplicație distribuită
care partajează procesarea între furnizorii de servicii numiți servere și elementele
care solicită, numite clienți. Clienții și serverele comunică printr-o rețea de
calculatoarea, de obicei prin Internet, având suporturi hardware diferite, dar pot
rula și pe același sistem fizic. Un server (fizic) rulează unul sau mai multe
programe server, care partajează resursele existente cu clienții. Clientul nu
partajează niciuna dintre resursele proprii, ci apelează la resursele serverului prin
funcții server. Clienții inițializează comunicația cu serverele și așteaptă mesajele
acestora. Prin menținerea legăturii între cei doi, indiferent de pauzele care intervin,
se folosește conceptul de sesiune, care de obicei este limitată în timp.
Socket este o interfață între un program de aplicație și serviciul de transport,
fiind furnizat de o bibliotecă sau de sistemul de operare. Se folosește conceptul de
descriptor, fiecare socket fiind tratat asemănător cu un fișier local. Acest descriptor
este transmis aplicației la crearea socket-ului și apoi est utilizat ca argument în
apelurile următoare.
În general, o conexiune de rețea se realizează dinspre o stație (host) numită
client, către o altă stație, numită server. Pentru ca un client să se poată conecta la
un server, are nevoie de două informații: adresa serverului și portul pe care ascultă
aplicația la care se dorește conectarea. Clasa care realizează acest lucru în Java se
numește java.net.Socket. Orice obiect de tip Socket, după instanțiere, are asociate
două stream-uri:
 un InputStream de pe care se pot citi date venite de la celălalt capăt al
conexiunii, accesând metoda Socket.getInputStream();
 un OutputStream pe care se pot scrie date pentru a fi trimise la celălalt
capăt al conexiunii, accesând cu metoda Socket.getOutputStream().

Rolul unui socket server este de a accepta conexiuni pe la unul sau mai mulți
clienți. Clasa care implementează acest comportament este java.net.ServerSocket.
Pentru ca un ServerSocket să poată funcționa, are nevoie de o singură informație,
și anume portul pe care să accepte conexiuni. Pentru a efectua o conectare
concretă, clasa conține o metodă numită accept().
Codul sursă:

Configurația serverului:
1. SERVER_HOST=127.0.0.1  
2. SERVER_PORT=12056  
3. SERVER_TIMEOUT=10000  
4. SERVER_MAX_CLIENTS=4  

Configurația clientului:
1. SERVER_HOST=127.0.0.1  
2. SERVER_PORT=12056  

Clientul
1. package client  
2.   
3. import com.sun.media.jfxmedia.logging.Logger  
4. import java.io.*  
5. import java.net.Socket  
6. import java.util.Properties  
7. import java.util.logging.Level  
8.   
9. object ChatClient {  
10.   
11.     private var connected = true  
12.     private var serverHost: String? = null  
13.     private var serverPort: Int? = null  
14.   
15.     private lateinit var socket: Socket  
16.     private lateinit var inputStream: BufferedReader  
17.     private lateinit var outputStream: PrintWriter  
18.   
19.     fun startClient() {  
20.         loadClientConfiguration()  
21.         connectToServer()  
22.   
23.         println("WELCOME")  
24.         try {  
25.             BufferedReader(InputStreamReader(System.`in`)).use { userInput ->  
26.                 while (connected) {  
27.                     try {  
28.                         if (inputStream.ready()) {  
29.                             val response = inputStream.readLine()  
30.                             if (response != "CONNECTION_TERMINATED") {  
31.                                 println(response)  
32.                                 print("> ")  
33.                             } else {  
34.                                 connected = false  
35.                             }  
36.                         }  
37.   
38.                         if (userInput.ready()) {  
39.                             outputStream.println(userInput.readLine())  
40.                             val response = inputStream.readLine()  
41.                             print("> ")  
42.                             if (response == null) {  
43.                                 println("ERROR: The connection to the server has been i
nterrupted.")  
44.                                 break  
45.                             } else if (response != "ACK") {  
46.                                 println(response)  
47.                             }  
48.                         }  
49.                     } catch (e: IOException) {  
50.                         println("ERROR: The connection to the server has been interrupt
ed.")  
51.                     }  
52.   
53.                 }  
54.                 closeConnectionToServer()  
55.                 println("Connection closed.")  
56.                 System.exit(0)  
57.             }  
58.         } catch (ioe: IOException) {  
59.             Logger.logMsg(Level.WARNING.intValue(), ioe.message)  
60.         }  
61.   
62.     }  
63.   
64.   
65.     private fun loadClientConfiguration() {  
66.         val config = Properties()  
67.         try {  
68.             FileInputStream("client.properties").use { inputStream ->  
69.                 config.load(inputStream)  
70.                 serverHost = config.getProperty("SERVER_HOST")  
71.                 serverPort = Integer.parseInt(config.getProperty("SERVER_PORT"))  
72.             }  
73.         } catch (e: Exception) {  
74.             println("ERROR. Please check client configuration.")  
75.             System.exit(1)  
76.         }  
77.     }  
78.   
79.     private fun connectToServer() {  
80.         try {  
81.             socket = Socket(serverHost, serverPort!!)  
82.             inputStream = BufferedReader(InputStreamReader(socket!!.getInputStream()))  
83.             outputStream = PrintWriter(socket!!.getOutputStream(), true)  
84.         } catch (e: IOException) {  
85.             println("ERROR. Please make sure it is online.")  
86.             closeConnectionToServer()  
87.             System.exit(1)  
88.         }  
89.     }  
90.   
91.     private fun closeConnectionToServer() {  
92.         try {  
93.             socket.let { it.close() }  
94.             inputStream.let { it.close() }  
95.             outputStream.let { it.close() }  
96.         } catch (e: IOException) {  
97.             println("ERROR. Can not close connection.")  
98.         }  
99.   
100.     }  
101. }  

Serverul
1. package server  
2.   
3. import java.io.FileInputStream  
4. import java.net.*  
5. import java.util.ArrayList  
6. import java.util.Properties  
7.   
8. object ChatServer {  
9.   
10.     private lateinit var host: InetAddress  
11.     private var port: Int = 0  
12.     private var timeout: Int = 0  
13.     private var maxClients: Int = 0  
14.     private var serverOnline = false  
15.   
16.     private var serverSocket: ServerSocket? = null  
17.     private var clients: ArrayList<Client>? = null  
18.   
19.     private val onlineUsers: ArrayList<String>  
20.         get() {  
21.             val onlineUsers = ArrayList<String>()  
22.             for (client in clients!!) {  
23.                 onlineUsers.add(client.getUser()!!.userName)  
24.             }  
25.             return onlineUsers  
26.         }  
27.   
28.   
29.     @Throws(Exception::class)  
30.     fun start() {  
31.         loadServerConfiguration()  
32.         serverSocket = ServerSocket(port, timeout, host)  
33.         serverOnline = true  
34.         println("SERVER: Server listening on $host:$port")  
35.   
36.         clients = ArrayList()  
37.         while (serverOnline) {  
38.             val client = Client(serverSocket!!.accept())  
39.             if (clients!!.size < maxClients) {  
40.                 clients!!.add(client)  
41.                 Thread(client).start()  
42.                 client.notify("SERVER: Connection to server established. Please log in.
")  
43.             } else {  
44.                 client.notify("SERVER: The chat server is currently full. Please try ag
ain later.")  
45.                 client.stop()  
46.             }  
47.         }  
48.     }  
49.   
50.     fun processInput(client: Client, input: String) {  
51.         client.notify("ACK")  
52.         val args = input.split("\\s".toRegex()).dropLastWhile { it.isEmpty() }.toTypedA
rray()  
53.         when (args[0]) {  
54.             "new" -> {  
55.                 if (client.getUser() != null) {  
56.                     client.notify("SERVER: You are already logged in")  
57.                 }  
58.   
59.                 val userName = args[1]  
60.                 val userPassword = args[2]  
61.   
62.                 if (userName.length > 31 || userPassword.length < 4 || userPassword.len
gth > 8) {  
63.                     client.notify("ERROR: Username must be less than 32 characters and 
password must be between 4-8 characters.")  
64.                 }  
65.   
66.                 if (User.register(userName, userPassword)) {  
67.                     client.notify("Registration successful. Please login.")  
68.                 } else {  
69.                     client.notify("ERROR: Username is already in use")  
70.                 }  
71.             }  
72.             "login" -> {  
73.                 try {  
74.                     if (client.getUser() != null) {  
75.                         client.notify("ERROR: You are already logged in")  
76.                     }  
77.                     val user = login(args[1], args[2])  
78.                     if (user == null) {  
79.                         client.notify("ERROR: Username or password incorrect.")  
80.                     } else {  
81.                         client.setUser(user)  
82.                         client.notify("Welcome, " + user.userName + "! You have been su
ccessfully logged in.")  
83.                     }  
84.                 } catch (e: Exception) {  
85.                     client.notify("ERROR: Invalid input. Please try again.")  
86.                 }  
87.   
88.             }  
89.             "send" -> {  
90.                 try {  
91.                     if (client.getUser() == null) {  
92.                         client.notify("ERROR: You must be logged in to send messages.") 
 
93.                     } else {  
94.                         val message = StringBuilder()  
95.                         val senderUserId = client.getUser()!!.userName  
96.                         for (i in 2 until args.size) {  
97.                             message.append(" ")  
98.                             message.append(args[i])  
99.                         }  
100.   
101.                         if (args[1] == "all") {  
102.                             ChatServer.broadcastMessage(senderUserId, "[$senderU
serId]:$message")  
103.                         } else {  
104.                             val receiverUserName = args[1]  
105.                             if (!ChatServer.sendMessage(senderUserId, receiverUs
erName, message.toString())) {  
106.                                 client.notify("ERROR: $receiverUserName is not o
nline")  
107.                             }  
108.                         }  
109.                     }  
110.                 } catch (e: Exception) {  
111.                     client.notify("ERROR: Invalid input. Please try again.")  
112.                 }  
113.   
114.             }  
115.             "online" -> if (client.getUser() != null) {  
116.                 val users = ChatServer.onlineUsers  
117.                 val response = StringBuilder("Online users: ")  
118.                 response.append(users.toString())  
119.                 client.notify(response.toString())  
120.             } else {  
121.                 client.notify("ERROR: You must be logged in to see a list of onl
ine users.")  
122.             }  
123.             "logout" -> {  
124.                 if (client.getUser() == null) {  
125.                     client.notify("ERROR: You are not logged in.")  
126.                 }  
127.                 logout(client)  
128.                 client.stop()  
129.             }  
130.             else -> client.notify("ERROR: Invalid input. Please try again.")  
131.         }  
132.     }  
133.   
134.     fun stop() {  
135.         serverOnline = false  
136.         try {  
137.             for (client in clients!!) {  
138.                 client.stop()  
139.             }  
140.             serverSocket!!.close()  
141.         } catch (e: Exception) {  
142.             println("SERVER ERROR: Server did not shutdown successfully.")  
143.         }  
144.     }  
145.   
146.     @Throws(Exception::class)  
147.     private fun loadServerConfiguration() {  
148.         val config = Properties()  
149.         FileInputStream("server.properties").use { inputStream ->  
150.             config.load(inputStream)  
151.             host = InetAddress.getByName(config.getProperty("SERVER_HOST"))  
152.             port = Integer.parseInt(config.getProperty("SERVER_PORT"))  
153.             timeout = Integer.parseInt(config.getProperty("SERVER_TIMEOUT"))  
154.             maxClients = Integer.parseInt(config.getProperty("SERVER_MAX_CLIENTS
"))  
155.         }  
156.     }  
157.   
158.     private fun login(userName: String, userPassword: String): User? {  
159.         for (user in User.getUsers()!!) {  
160.             if (user.userName == userName && user.userPassword == userPassword) 
{  
161.                 broadcastMessage(userName, "$userName joined")  
162.                 return user  
163.             }  
164.         }  
165.         return null  
166.     }  
167.   
168.     private fun broadcastMessage(sender: String, message: String) {  
169.         for (client in clients!!) {  
170.             if (client.getUser() != null && client.getUser()!!.userName != sende
r) {  
171.                 client.notify(message)  
172.             }  
173.         }  
174.         println("> $message")  
175.     }  
176.   
177.     private fun sendMessage(sender: String, userId: String, message: String): Bo
olean {  
178.         for (client in clients!!) {  
179.             if (client.getUser()!!.userName == userId) {  
180.                 client.notify("[$sender]:$message")  
181.                 println("> [$sender] (to $userId): $message")  
182.                 return true  
183.             }  
184.         }  
185.         return false  
186.     }  
187.   
188.     private fun logout(client: Client) {  
189.         clients!!.remove(client)  
190.         val userName = client.getUser()!!.userName  
191.         broadcastMessage(userName, "$userName left")  
192.     }  
193. }  

1. package server  
2.   
3. import java.io.BufferedReader  
4. import java.io.IOException  
5. import java.io.InputStreamReader  
6. import java.io.PrintWriter  
7. import java.net.Socket  
8.   
9. class Client @Throws(IOException::class) constructor(clientSocket: Socket) : Runnable { 
 
10.   
11.     private var connected = true  
12.     private var user: User? = null  
13.   
14.     private val inStream: BufferedReader = BufferedReader(InputStreamReader(clientSocke
t.getInputStream()))  
15.     private val outStream: PrintWriter = PrintWriter(clientSocket.getOutputStream(), tr
ue)  
16.   
17.     override fun run() {  
18.         var input: String  
19.         try {  
20.             while (connected) {  
21.                 input = inStream.readLine()  
22.                 if (input != null) {  
23.                     ChatServer.processInput(this, input)  
24.                 }  
25.             }  
26.         } catch (e: IOException) {  
27.             outStream.println("SERVER ERROR: Invalid input. Please try again.")  
28.         }  
29.   
30.     }  
31.   
32.     fun notify(message: String) {  
33.         outStream.println(message)  
34.     }  
35.   
36.     fun stop() {  
37.         connected = false  
38.         closeConnection()  
39.     }  
40.   
41.     fun getUser() = user  
42.   
43.     fun setUser(user: User) {  
44.         this.user = user  
45.     }  
46.   
47.     private fun closeConnection() {  
48.         try {  
49.             with(outStream) {  
50.                 print("CONNECTION_TERMINATED")  
51.                 close()  
52.             }  
53.             inStream.close()  
54.         } catch (e: Exception) {  
55.             println("SERVER ERROR: Exception $e")  
56.         }  
57.     }  
58.   
59. }  
60. package server  
61.   
62. import java.io.*  
63. import java.util.ArrayList  
64.   
65. class User private constructor(  
66.     val userName: String,  
67.     val userPassword: String  
68. ) : Serializable {  
69.   
70.     companion object {  
71.   
72.         private var users: ArrayList<User>? = null  
73.         private val userFile = System.getProperty("user.dir") + "/users.txt"  
74.   
75.         fun register(userId: String, password: String): Boolean {  
76.             if (users == null) { loadUsers() }  
77.             val user = User(userId, password)  
78.             for (existingUser in users!!) {  
79.                 if (existingUser.userName === userId) {  
80.                     return false  
81.                 }  
82.             }  
83.             users!!.add(user)  
84.             return saveUsers()  
85.         }  
86.   
87.         private fun loadUsers(): Boolean {  
88.             val fileInputStream: FileInputStream  
89.             val objectInputStream: ObjectInputStream  
90.             users = ArrayList()  
91.   
92.             val file = File(userFile)  
93.             try {  
94.                 file.createNewFile()  
95.   
96.                 fileInputStream = FileInputStream(file)  
97.                 objectInputStream = ObjectInputStream(fileInputStream)  
98.   
99.                 var user: User  
100.                 while ((objectInputStream.readObject() as User) != null) {  
101.                     user = objectInputStream.readObject() as User  
102.                     users!!.add(user)  
103.                 }  
104.                 objectInputStream.close()  
105.                 fileInputStream.close()  
106.             } catch (e: Exception) {  
107.                 return false  
108.             }  
109.             return true  
110.         }  
111.   
112.         private fun saveUsers(): Boolean {  
113.             val file = File(userFile)  
114.             try {  
115.                 file.createNewFile()  
116.                 val fileOutputStream = FileOutputStream(file, false)  
117.                 val objectOutputStream = ObjectOutputStream(fileOutputStream)  
118.                 for (user in users!!) {  
119.                     objectOutputStream.writeObject(user)  
120.                 }  
121.                 objectOutputStream.close()  
122.                 fileOutputStream.close()  
123.             } catch (e: Exception) {  
124.                 return false  
125.             }  
126.   
127.             return true  
128.         }  
129.   
130.         fun getUsers(): ArrayList<User>? {  
131.             if (users == null) { loadUsers() }  
132.             return users  
133.         }  
134.   
135.     }  
136. }  
Figura 1. Urmărirea acțiunilor pe server.

Figura 2. Clientul 1

Figura 3. Clientul 2

Concluzii:
Elaborând această lucrare de laborator am făcut cunoștință conceptul de Socket și
tehnicile de programare în rețea utilizând socket-uri. Operațiile pe un socket pot fi
asemănate cu operațiile de IO pe un fișier, socket-ul fiind asociat handle-ului pe
fișier. Scoket-urile pot fi folosite pentru a face două aplicații să comunice între ele.

S-ar putea să vă placă și