COM-Schnittstelle --> Websocket

tsurt

Grünschnabel
Hallo,

ich will einen Java-Websocket-Server programmieren, der auf einem Linux/Windowsrechner läuft, die serielle Schnittstelle ausliest und die empfangenen Daten an die über den Socket verbundenen Klienten weitergibt. Damit will ich Echtzeit simulieren. Ich bekomme es einfach nicht gebacken, die empfangenen Daten an die Nutzer zu verteilen. Ich will auch keine großartigen APIs verweden , sondern es mit eigenen Mitteln hinbekommen!

Nach einer ausgiebigen Recherche habe ich folgenden Server, der eine Verbindung aufbaut, ich kann bzw konnte auch schon Daten an den Browser senden, die mir dort angezeigt worden sind, aber halt immer nur bei dem einen Klient und nicht bei allen.

Im Grunde habe ich folgendes:

Die server.java startet den Server und erstellt für jeden Benutzer einen Thread:

Code:
public class server {

	private int portName;
	private static String com = "COM1";
	SerialPort serialPort;
	private ServerSocket ss = null;
	boolean serverAn = true;
	public Hashtable<String, Integer> klienten = new Hashtable<String, Integer>();

	public server(int port) {
		this.portName = port;
	}

	public void startOpenComConnection() throws NoSuchPortException,
			PortInUseException, UnsupportedCommOperationException, IOException {
		CommPortIdentifier portIdentifier = CommPortIdentifier
				.getPortIdentifier(com);
		if (portIdentifier.isCurrentlyOwned()) {
			System.out.println("Error: Port is currently in use");
		} else {
			CommPort commPort = portIdentifier.open(com, 2000);

			if (commPort instanceof SerialPort) {
				serialPort = (SerialPort) commPort;
				serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,
						SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
			}
		}
		InputStream serialInput = serialPort.getInputStream();
		(new Thread(new SerialReader(serialInput))).start();

	}

	public void starteServer() throws Exception {

		ss = new ServerSocket(portName);

		while (serverAn) {
			Socket socket = ss.accept();

			benutzerThread benutzerThread = new benutzerThread(socket,
					this);
			benutzerThread.start();
		}
		try {
			ss.close();
			System.out.println("Server gestoppt!");
		} catch (Exception ex) {
			System.out.println("Problem: Socket konnte nicht gestoppt werden!");
			System.exit(-1);
		}
	}

}

und die Klasse die für jeden Benutzer erstellt wird:

Code:
public class benutzerThread extends Thread {
	Socket socket;
	server server;
	BufferedReader in;
	BufferedOutputStream out;
	static int verbundeneNutzer = 0;

	public benutzerThread(Socket socket, server server) {
		this.socket = socket;
		this.server = server;
	}

	@Override
	public void run() {
		PrintWriter prw = null;
		verbundeneNutzer++;
		String user = "Nutzer " + verbundeneNutzer;
		while (true) {

			try {
				String strStream = null;

				prw = new PrintWriter(socket.getOutputStream());
				strStream = doRead(socket.getInputStream());

				HTTPRequest req = new HTTPRequest();
				String strKey = req.getParameter(strStream,
						"Sec-WebSocket-Key".toLowerCase());

				strKey = KeyGeneration.getKey(strKey);

				writeHeaders(prw, strKey);

				server.klienten.put(user, verbundeneNutzer);
				System.out.println(user);

				schreibeNachrichtAnNutzer("Server:" + user
						+ " entered the room");

				System.out.println(verbundeneNutzer);

			} catch (Exception e) {
				prw.write("Exception occurred processing request: "
						+ e.toString());
				prw.flush();
				prw.close();
				

			} finally {
				try {
					
					//socket.close();
				} catch (Exception e) {
					// ignore
				}
			}
		}
	}

	private String doRead(InputStream in) throws Exception {

		byte[] data = new byte[1024 * 4];

		int iBytesRead = in.read(data);
		return new String(data).substring(0, iBytesRead);
	}

	/**
	 * Write our headers to complete the connection
	 * 
	 * @param out
	 * @param strSecKey
	 *            -- Derived from the cliet key.
	 * @see KeyGeneration.java
	 * @throws Exception
	 */
	private void writeHeaders(PrintWriter out, String strSecKey)
			throws Exception {

		String strHeaders = "HTTP/1.1 101 Switching Protocols\r\n"
				+ "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n"
				+ "Sec-WebSocket-Accept: " + strSecKey + "\r\n" + "\r\n";
		out.write(strHeaders);
		out.flush();
	}

	public void schreibeNachrichtAnNutzer(String strText) throws IOException {

		final byte SINGLE_FRAME_UNMASKED_MESSAGE = (byte) 0x81;
		byte[] textBytes = strText.getBytes("UTF-8");

		BufferedOutputStream os = new BufferedOutputStream(
				socket.getOutputStream());
		ByteArrayOutputStream bao = new ByteArrayOutputStream();
		/* Add start of Frame */
		bao.write(SINGLE_FRAME_UNMASKED_MESSAGE);
		bao.write((byte) textBytes.length);
		bao.write(textBytes);

		bao.flush();
		bao.close();

		os.write(bao.toByteArray(), 0, bao.size());
		os.flush();

	}
}

Im Moment bekommt jeder Klient eine Willkommensnachricht gesendet, aber immer nur der, der sich gerade verbunden hat!

Könnt ihr mir Tipps oder Hilfestellungen geben, wie ich das ganze so hinbekomme, dass ich die Benutzer, die sich verbunden haben, zusammenfassen kann, und dann an alle eine Nachricht senden kann?

Ich kann diese ja in einer Liste speicher, aber irgendwie kann ich auch nicht abfangen, wann ein Klient die Verbindung schließt. Das erschwert das ganze natürlich!


Ich danke schon mal im Vorraus für kreative Ideen!
 
Hallo,

die eigentliche Fragestellung hat sich erledigt,habe das Problem lösen können, in dem ich Threads in einem Vektor abgelegt habe, den ich dann durch iterieren kann!
Dabei ergab sich ein neues Problem:

Ich lese die COM-Schnittstelle mit der rxtx-Erweiterung aus. Wenn ich das java lokal auf dem Windowsrechner laufen lasse, funktioniert das auch. Ändere ich meinen Code ab und starte den Server auf meinem Linuxrechner, funktioniert das auslesen erst einmal wunder prächtig, doch nach ca 20 Zeichen schmeißt die Erweiterung eine Fehlermeldung und der COM-Port wird geschlossen. Es is eine IOException.

Code:
lllkjuioztrrjava.io.IOException: Input/output error in nativeavailable
        at gnu.io.RXTXPort.nativeavailable(Native Method)
        at gnu.io.RXTXPort$SerialInputStream.read(RXTXPort.java:1373)
        at gnu.io.RXTXPort$SerialInputStream.read(RXTXPort.java:1287)
        at SerialReader.run(SerialReader.java:19)
        at java.lang.Thread.run(Thread.java:636)

Gibt es noch andere Möglichkeiten eine serielle Schnittstelle auszulesen?
 
Zuletzt bearbeitet:
Ich gehe mal davon aus, dass du unter Linux nicht die notwendigen Rechte hast, auf die COM-Schnittstelle zuzugreifen. Je nach Distribution solltest du mal nachschauen, ob du Regeln für udev, SELinux oder AppArmor findest, die es zulassen, die Schnittstelle auszulesen.
 
Also da es eine Debian-Distribution ist, wird wohl udev verwendet. Aber sehe ich das nicht richitg, dass Linux es gar nicht erst zulassen würde, dass auf die COM-Schnittstelle zu griffen wird, falls keine Rechte dazu da sind? Ich meine, es is ja komisch, dass es erst geht, aber dann nach 20 Zeichen der Fehler erscheint...

Lass ich den Server auf Windows laufen, und connecte mich mit minicom auf den com port, geht es ja auch.. und da bricht nichts ab!
 
Vielleicht macht die Java-API irgend einen Quatsch, ließt z.B. die Zeihen der Fehlermeldung aus…
Kannst du dir die 20 Zeichen mal etwas genauer anschauen? Im Normallfall solltest du aber als Nutzer keine Rechte haben, COM-Devices auszulesen. Vielleicht hast du hier noch ein weiteres Problem.
Alternativ kann man unter Linux auch das Gerät selbst wie eine Datei auslesen, du müsstest die Datei irgendwo unter /dev/ finden, damit kannst du es ja mal testen. Die Datei sollte man auch mit Java auslesen können.
 
Also erstmal zu den Rechten, die Rechte hab ich natürlich angepasst und neu gesetzt! Ich hab mir dann mal zum testen einen serielle zu usb -Adapter besorgt, und siehe da alles funktioniert! Ich hab inzwischen im Verdacht, dass die Konsole des NanosG20 auf den ttyS1 umgeleitet wird, und der Java-Treiber damit Problemen hat, weil er falschen Input bekommt.

Ich werde das mal weiter testen!

Ich hab noch mal eine Frage zu der Websocketgeschichte... Ist es irgendwie möglich den abzufangen ob ein Browser am Socket verbunden ist? Also so dass ich den Thread wieder aus dem Vektor löschen kann sobald der Nutzer den Browser schließt, oder die Verbindung verliert?
 
Erstmal tut mir leid, dass ich ein Doppelpost mache, aber irgendwie komm ich nicht weiter! Das oben genannte Problem ist für mich auch noch nicht gelöst. Also ich hab keine Möglichkeit gefunden, den Nutzer wieder zu löschen. Aber die werde ich schon noch finden!

Hier zu meinem nächsten Problem. Unten angefügt die Klasse die die R232 Schnittstelle ausließt. Aber ich bekomme keine ordentlich lesbaren Daten herrein, sondern nicht lesbare Zeichen. Wenn ich die Kommunikation mit einem Portmonitor anschau, dann kommen lesbare Daten raus, entweder die einzelnen Byte in Schrift oder als Hexadezimal dargstellt. Mir isses ja erstmal egal wie sie dargestellt werden, aber es mir doch was anzeigen, mit dem man was anfangen kann, oder?

Nun hab ich mich durch google durchgefressen, alle möglichen anderen Methoden zum auslesen ausprobiert. aber nichts funktioniert! Habt ihr vlt eine Idee? Ich wäre euch echt dankbar!


Ausgabe SerialPortMonitor:
Code:
00 00 00 00
00 00 00 00
02 00 00 00
00 00 FF 00
00 00 00 1C
E5 03      
00 00 00 00
00 00 00 00
02 00 00 00
00 00 FF 00
00 00 00 1C
E5 03      
00 00 00 00
00 00 00 00
02 00 00 00
00 00 FF 00
00 00 00 1C
E5 03      
00 00 00 00
00 00 00 00


Code:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.nio.CharBuffer;
import java.util.Arrays;

public class SerialReader implements Runnable {
	InputStream in;
	BufferedOutputStream os = null;
	Socket socket;

	public SerialReader(InputStream in) throws UnsupportedEncodingException {
		this.in = in;
	}

	public void run() {
		   byte[] buffer = new byte[20];
		    int len = -1;
		    // the read can throw
		    try {
		        while ((len = in.read(buffer)) > -1) {
		            if (len > 0) {
		                final String part = new String(buffer, "UTF8");
		               System.out.print(part);
		            }
		            try {
		                Thread.sleep(50);
		            } catch (InterruptedException e) {
		                break;
		            }
		        }
		    } catch (IOException e) {
		        e.printStackTrace();
		    }
	}
}
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück