
Websockets पर Race Conditions प्रदर्शित करने के लिए सरल PoC
सूचना प्रौद्योगिकी के क्षेत्र में, डेटा विश्वसनीयता और अखंडता सुनिश्चित करना महत्वपूर्ण है, विशेष रूप से जब लाखों उपयोगकर्ता और टेराबाइट्स डेटा शामिल हों। हालाँकि, जैसे-जैसे सॉफ़्टवेयर सिस्टम अधिक जटिल होते जाते हैं, रेस कंडीशन्स जैसी समस्याएँ उत्पन्न हो सकती हैं, जो सिस्टम संचालन को महत्वपूर्ण रूप से प्रभावित करती हैं और अप्रत्याशित परिणामों को जन्म देती हैं।
रेस कंडीशन्स वे त्रुटियाँ हैं जो मल्टीटास्किंग प्रोग्राम्स में तब होती हैं जब दो या अधिक थ्रेड्स या प्रोसेस बिना सिंक्रोनाइज़ेशन के एक साथ साझा डेटा या संसाधनों को संशोधित करने का प्रयास करते हैं। इसके परिणामस्वरूप अप्रत्याशित और अनिश्चित परिणाम हो सकते हैं क्योंकि संचालन के निष्पादन का क्रम इस पर निर्भर करता है कि कौन से थ्रेड्स या प्रोसेस पहले समाप्त होते हैं। रेस कंडीशन्स का पता लगाना सॉफ़्टवेयर सिस्टम्स में एक चुनौतीपूर्ण समस्या है क्योंकि उनकी प्रकृति अप्रत्याशित होती है।
हालाँकि इंटरनेट पर क्लासिक रेस कंडीशन्स के बारे में कई संसाधन उपलब्ध हैं, यह लेख यह पता लगाता है कि क्या वेबसॉकेट में रेस कंडीशन्स हो सकती हैं।
वेबसॉकेट एक अत्याधुनिक तकनीक है जो उपयोगकर्ता के वेब ब्राउज़र और वेब सर्वर के बीच एक खुला द्विदिशात्मक कनेक्शन प्रदान करके वेब अनुप्रयोगों में इंटरैक्शन को महत्वपूर्ण रूप से बेहतर बनाती है। यह निर्बाध कनेक्शन लगातार नए HTTP अनुरोध शुरू करने की आवश्यकता के बिना डेटा विनिमय को सक्षम बनाता है, जिससे ये इंटरैक्टिव अनुप्रयोगों को बनाने के लिए आदर्श बन जाते हैं।
अवधारणा को प्रदर्शित करने के लिए, इस लेख में एक Java कोड शामिल है जो एक वेबसॉकेट सर्वर का प्रतिनिधित्व करता है जो PostgreSQL डेटाबेस के साथ इंटरैक्ट करता है। सर्वर वेबसॉकेट कनेक्शन को संभालने के लिए Java-WebSocket लाइब्रेरी का उपयोग करता है और निम्नलिखित कार्य करता है:
प्रोग्राम लॉन्च करने के बाद, Java कोड डेटाबेस से कनेक्ट होता है और जाँचता है कि "example" तालिका मौजूद है या नहीं। यदि यह मौजूद नहीं है, तो यह तालिका बनाता है और यादृच्छिक डेटा डालता है:
सबसे दिलचस्प कोड "onMessage" फ़ंक्शन में पाया जाता है।
public static int a = 0;
@Override
public void onMessage(WebSocket conn, String message) {
if (a == 0) {
try {
// some activity with db
int rowCount = getCountFromExampleTable();
} catch (SQLException e) {
System.out.println("Error executing query: " + e.getMessage());
}
conn.send("Echo: " + message);
a = a + 1;
System.out.println(a);
}
}
एक ग्लोबल वेरिएबल "a" है जो 0 पर इनिशियलाइज़ किया गया है। जब कोई क्लाइंट सर्वर से कनेक्ट होता है और एक संदेश भेजता है, तो यह जाँचता है कि "id == 0" है या नहीं, जो दर्शाता है कि यह फ़ंक्शन पहले ही निष्पादित हो चुका है या नहीं। यदि नहीं, तो "example" तालिका से पंक्तियों की गणना चुनने के लिए एक सरल SQL कमांड निष्पादित की जाती है। फिर, "a" को 1 से बढ़ाया जाता है, और इसका मान प्रिंट किया जाता है। और सिद्धांत रूप में, फ़ंक्शन को 2 बार निष्पादित नहीं किया जाना चाहिए।
क्लाइंट के संबंध में, दो प्रकार के क्लाइंट बनाए गए हैं: "WebSocketParallel_Success"
package io.redrays.ws.concept.client;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class WebSocketParallel_Success {
public static void main(String[] args) {
// Define the WebSocket server URI
String serverUri = "ws://127.0.0.1:8080";
// Number of WebSocket clients to create
int numClients = 100;
// Create an ExecutorService to manage multiple WebSocket client threads
ExecutorService executor = Executors.newFixedThreadPool(numClients);
// Create a list to store WebSocket client instances
List<WebSocketClient> clients = new ArrayList<>();
// Loop to create and configure multiple WebSocket clients
for (int i = 0; i < numClients; i++) {
int clientId = i + 1;
try {
// Create a WebSocket client for each connection
WebSocketClient webSocketClient = new WebSocketClient(new URI(serverUri)) {
@Override
public void onOpen(ServerHandshake handshakedata) {
// Handle WebSocket connection opened event
System.out.println("Client " + clientId + " connected to the WebSocket server");
this.send("Hello, WebSocket server! From client " + clientId);
}
@Override
public void onMessage(String message) {
// Handle incoming WebSocket messages
System.out.println("Client " + clientId + " received message: " + message);
}
@Override
public void onClose(int code, String reason, boolean remote) {
// Handle WebSocket connection closed event
System.out.println("Client " + clientId + " connection closed: " + reason);
}
@Override
public void onError(Exception ex) {
// Handle WebSocket error
System.out.println("Client " + clientId + " error occurred: " + ex.getMessage());
}
};
// Add the WebSocket client to the list
clients.add(webSocketClient);
// Connect the WebSocket client in a separate thread
executor.submit(webSocketClient::connect);
} catch (URISyntaxException e) {
System.out.println("Invalid WebSocket server URI: " + e.getMessage());
}
}
// Shutdown the executor after all tasks are submitted
executor.shutdown();
// Wait for all WebSocket client threads to complete
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
System.out.println("Interrupted while waiting for tasks to complete: " + e.getMessage());
}
}
}
और "WebSocketParallel_Failed"।
package io.redrays.ws.concept.client;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class WebSocketParallel_Failed {
public static void main(String[] args) {
String serverUri = "ws://127.0.0.1:8080"; // WebSocket server URI
int numParallelRequests = 285; // Number of parallel WebSocket requests
try {
WebSocketClient webSocketClient = new WebSocketClient(new URI(serverUri)) {