I am trying to send RDF/XML from a Client to a Server using sockets in Java. When I send the information the Server program hangs and does not receive the info unless I close the Socket or OutputStream on the Client side. Even if I flush the OutputStream on the Client-side the Server does not receive the data unless I close the Socket/Stream. I would like to send the information without closing the socket. Here is some example code for the Client (using Sesame):
import java.io.*;
import java.net.*;
import org.openrdf.rio.*;
import org.openrdf.rio.helpers.*;
import org.openrdf.model.URI;
import org.openrdf.model.Model;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.Statement;
import org.openrdf.model.impl.*;
import org.openrdf.model.vocabulary.*;
public class SimpleRDFClient {
private Socket socket = null;
public static void main(String[] args) {
new SimpleRDFClient(args[0],Integer.parseInt(args[1])).launch();
}
public SimpleRDFClient(String host, int port) {
try {
socket = new Socket(host,port);
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void launch() {
try {
OutputStream out = socket.getOutputStream();
BufferedOutputStream dos = new BufferedOutputStream(out);
Model model = new LinkedHashModel();
ValueFactory factory = new ValueFactoryImpl();
URI clive = factory.createURI("http://www.site.org/cliveAnderson");
Statement st = factory.createStatement(clive, RDF.TYPE, FOAF.PERSON);
model.add(st);
Rio.write(model,dos,RDFFormat.RDFXML);
dos.flush();
//Some other stuff
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
And the Server Handler:
import java.io.*;
import java.net.*;
import org.openrdf.rio.*;
import org.openrdf.rio.helpers.*;
import org.openrdf.model.*;
import org.openrdf.model.impl.*;
public class SimpleRDFSHandler implements Handler {
public void handleConnection(Socket socket) {
Model model = null;
try {
InputStream in = socket.getInputStream();
model = Rio.parse(in,"www.blah.com",RDFFormat.RDFXML);
for (Statement st: model) {
System.out.println(st);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
The problem seems to come from the Rio.parse() method hanging (I think because it does not know when the input ends). I get a similar problem when I use the Jena api in a similar way, i.e. using Model.write(outputstream,format) and Model.read(inputstream,format) instead of Rio. I have looked at the source and the javadoc for ages but can't solve the problem. I think it must be something simple I have misunderstood. Any ideas?
I don't think this is in any way a Jena/Sesame specific issue but rather a Java issue around your use of sockets. Is there actually a practical reason you want to not close the socket?
I don't see why this would ever be advisable unless you want to continuously post data and process it as it is received on the server side? If this is the case both Jena and Sesame have APIs that specifically allow you to control what happens to data as it parsed in so that you aren't reliant on your read calls from completing before you process the data.
Also why use sockets, both Sesame and Jena have comprehensive HTTP integration which is much easier to use and deploy than rolling your own socket based server and clients.
The Ugly Hacky Solution
If you really must do this then there is a workaround but it is somewhat horrid and fragile and I would strongly recommend that you do not do this.
On the client side after you write the data write a sequence of bytes that indicate end of stream. On the server side wrap the socket stream with a custom InputStream implementation that recognizes this sequence and stops returning data when it is seen. This should allow the Jena/Sesame code which is expecting the stream to finish to function correctly.
The sequence of bytes need to be carefully chosen such that it won't naturally occur in the data.
To be honest this is a terrible idea, if your aim is to continuously post data this won't really solve your problem because then you'll just be leaking sockets server side unless you put the server side socket handling code in a while (true) loop which is likely another bad idea.
Related
I am building a server. I hope that after the Java server and the C# client are connected, I can send information from the HTML to the Java server, and then the Java server sends this information to the client.But I can't get the socket after the successful establishment in the service layer, so my Java server can only send fixed information to the client.
I tried using Class object = new Class(); object.setObject(socket); to save the socket, but when I call this object in the service layer, I get null;
I tried to save the socket using (Map) socket.put("socket", socket), but when I call this method in the service layer, I get null.
This is the code to make the socket. from SocketThread.java
public void run() {
ServerSocket serverSocket = null;
try{
serverSocket = new ServerSocket(5656);
LOGGER.info("socket server start, monitor 5656 port ! ");
Socket socket = serverSocket.accept();
new SocketClientRequest(socket).start();
LOGGER.info("send success ! ");
}catch (Exception ex){
LOGGER.error("send fail ! ");
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
LOGGER.error("服务器延时重启失败 ! ");
}
}
This is a method of reading the information sent by the client using the socket and sending the information to the client. from SocketClientRequest.java
public void run() {
try {
//获取socket中的数据
bufferedInputStream = new
BufferedInputStream(socket.getInputStream());
byte[] clientCharStream = new byte[messageLengthBytes];
bufferedInputStream.read(clientCharStream);
System.out.println(new String(clientCharStream, "utf-8"));
OutputStream out = socket.getOutputStream();
out.write(new String("welcome_send_server!").getBytes());
} catch (IOException e) {
LOGGER.error("read massage error [{}]", e);
}
}
Create a connection when the project starts
#EnableScheduling
#SpringBootApplication
public class GzserverApplication {
public static void main(String[] args) {
SpringApplication.run(GzserverApplication.class, args);
SocketServer socketServer = new SocketServer();
socketServer.start();
}
}
Until this step, everything is fine, but the key problem is coming.
I need to send information to the client through my controller.
this is controller
#ResponseBody
#RequestMapping(value = "firstSend)
public SResult<String> firstSend(String uName, String pNum, String time){
try{
return httpService.firstSend(uName, pNum, time);
}catch (Exception ex){
LOGGER.error(ex.getMessage(), ex);
}
return SResult.failure("fail of connect");
}
this is service
public SResult<String> firstSend(String uName, String pNum, String time) throws Exception {
String token = TokenUtil.sign(uName);
System.out.println("token code : "+token);
SocketObject socketObject = new SocketObject();
Map<String, Socket> socketMap = socketObject.socket();
Socket socket1 = socketMap.get("Socket"); // is null
Socket socket2 = socketObject.getSocket(); // is null
return SResult.success(token);
}
I hope that after the connection is successfully created, the socket can be used in the service layer, and the information is sent to the client through the socket, but no matter what I do, the socket is null in the service layer.please give me a help, thank you very much
You should not be dealing with Sockets if using Spring. Spring is a very extensive abstraction layer, that lets you avoid having to deal with the nasty details that Sockets introduce.
In your controller, you call: SocketObject socketObject = new SocketObject(); This creates a new object, presumably with a null-initialized Socket object. Nowhere in this code do you pass a socket object from the main() scope to any other scope (for example using a method named setSocket(Socket socket).
However, and I cannot stress this enough, you should not use Sockets in Spring. Think about what problem you are trying to solve, and ask yourself (why do I need to send information to the client). It is likely that Spring has a module that will do this for you in a much more scalable and manageable way.
For example, perhaps you need to establish 2-way communication between the server and the client, and need to post information to the client periodically. In this case, the WebSocket protocol (and associated Spring Websocket library) might be for you.
This is likely an XY problem. If you edit your question to illustrate the functionality you are trying to implement, it may be easier to help
CONTEXT:
I am creating a cross-platform multicast client-server system for mobile. I have created the server side in Java. I also created the android client side and it works perfectly.
WHAT I WANT TO KNOW:
I want to know if I could create a client side in iOS using the listener program in this example http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html that would be compatible with my server-side that I created in Java.
If the above example will not work is there a way I can still use my Java server-side and create a native iOS client system that is compatible with the Java server-side?
SAMPLE CODE OF JAVA SERVER SIDE FOR REFERENCE:
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
//more imports...
class Server2 {
public static MulticastSocket ms1;
public static void main(String[] args) throws IOException {
try {
InetAddress sessAddr1 = InetAddress.getByName("224.2.76.24");
ms1 = new MulticastSocket(5500);
ms1.joinGroup(sessAddr1);
while(true) {
byte[] message = new byte[1024];
message = getIpAddress().getBytes();
DatagramPacket dp = new DatagramPacket(message, message.length, sessAddr1, 5500);
ms1.send(dp);
System.out.println(String.format("Sent message: %s", message));
Thread.sleep(1000);
}
} catch (Exception e) {
System.out.println(String.format("Error: %s", e));
}
}
public static String getIpAddress() {
InetAddress ip;
try {
ip = InetAddress.getLocalHost();
return(String.format("%s",ip.getHostAddress()));
} catch (Exception e) {
return("false");
}
}
}
I tested the listener code in the link and it worked perfectly.
Should not be a problem. iOS is POSIX compliant and Objective-C is defined on top of ANSI C, so you could paste the code you linked to with minor modifications straight into your project, build a simple wrapper to Objective-C and your app should compile, run and work as desired.
I'm kinda new to the world of threading, and I'm making a game server, assigning every client who connects to another thread so I can accept multiple clients on the same port. However, I'm having an issue with clients connecting to the server, but not being able to send data (in the format of an ObjectOutputStream to the server). Any pointers on what could be going wrong?
Here's my code for my MatchmakingServer.java
try {
listenForPlayers = new ServerSocket(portNumber);
System.out.println("Port opened. Searching for players");
while (true){
Socket clientSocket = listenForPlayers.accept();
Runnable r = new PlayerHandlerForServer(clientSocket);
new Thread(r).start();
}
} catch (Exception e) { }
My PlayerHandler object implements Runnable and here's its run method.
private Player player;
private ObjectInputStream getPlayerData;
private static PrintWriter sendPlayerData;
private Socket socket;
public void run() {
try {
getPlayerData = new ObjectInputStream(socket.getInputStream());
player = (Player) getPlayerData.readObject();
//do stuff with the player object, this code get executed.
sendPlayerData = new PrintWriter(socket.getOutputStream(),true);
updatePlayersFound(sendPlayerData);
} catch (Exception e) { }
}
As pointed in the comments log the exceptions, they will provide a clue as to what might be causing this problem.
A wild guess would be that your Player class does not implement the Serializable interface.
I'm wondering why you're reading serialized objects from the Socket, but writing out data using a PrintWriter. I would suggest using the ObjectOutputStream and being consistent.
Sending serialized objects might be overkill. There could be more data being sent then you care about. This could cause useless network lag to your game clients! You might want to look at using DataInputStream / DataOutputStream. This would allow you to write / read objects only using what's really necessary.
I've just started looking at HTTP etc. and have written a simple Java Client that uses URLConnection to send a URL to a server and pulls down the index.html page (as plain text).
Now I'm working on a simple server but I'm stuck at the first hurdle, (well maybe 2nd or 3rd), I can't get it to respond to the client properly.
Here is the reading in loop and it reads in the HTTP request fine, even from FF and IE etc:
while((message = in.readLine()) != null)
{
System.out.println(message);
out.write("something");
}
The problem is that I don't know how to get it to respond anything useful. If I let it do what it is doing in the above code it sends "something" 6 times to my client (as there are 6 lines to the HTTP request) but nothing to FF/IE etc.
Also, it doesn't seem to break the loop ever as I added a System.out.println("test"); line to print after the loop but the server never seems to reach that point, should it? Should readLine() return null at the end of the first HTTP request?
I've been reading stuff on the sun and oracle websites but am still pretty stuck as to how this should work.
Thanks for your time,
Infinitifizz
EDIT: Oops, forgot to copy the code in.
Server.java:
package exercise2;
import java.net.*;
public class Server
{
public static void main(String[] args) throws Exception
{
boolean listening = true;
ServerSocket server = new ServerSocket(8081);
while(listening)
{
Socket client = server.accept();
new ServerThread(client).start();
}
server.close();
}
}
ServerThread.java:
package exercise2;
import java.io.*;
import java.net.*;
public class ServerThread extends Thread
{
private Socket socket = null;
public ServerThread(Socket s)
{
this.socket = s;
}
public void run()
{
try
{
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
String message, reply = "";
while((message = in.readLine()) != null)
{
System.out.println(message);
out.write("something");
}
System.out.println("test");
in.close();
out.close();
socket.close();
}
catch(IOException e)
{
System.err.println("error");
}
}
}
Without seeing your client code, this is my best guess as to what's happening:
Your server is probably blocking in that readLine() because the client is done writing the request, but hasn't closed the connection (as it should: the client should wait around to get the response over that same connection). Typically, a HTTP server parses a request as it reads it: based on this, you can look for "\r\n\r\n" to demarcate the end of the header, and break out of your read loop at that point to parse the request and respond to it.
First of all, change the condition in the while loop to
while(in.hasNextLine()) {
message = in.nextLine();
//etc....
Secondly, you don't need to exit out of the while loop while running a server. You should do all the parsing for requests inside the while loop, using if statements to distinguish the requests. The only time you would ever exit the while loop is when the connection should close, otherwise, the nextLine() method will block until something is received.
i am trying to code a small XMPP gtalk client in java. I know there is a lot of libraries that help you that but the RFC is so easy to understand that i decide to write a client by myself.
I know that the gtalk server is talk.google.com:5222 but when i try this small program i get this result :
HTTP/1.1 302 Found
Location: http://www.google.com/talk/
Content-Type: text/html
Content-Length: 151
<HTML><HEAD><TITLE>302 Moved</TITLE></HEAD><BODY><H1>302 Moved</H1>The document has moved here.</BODY></HTML>
I also tried to connect the location specified but it doesn't work. Here is my code in java :
package fr.grosdim.myjabber;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocketFactory;
/**
* Hello world!
*
*/
public class App {
public static void main(String[] args) {
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory
.getDefault();
try {
Socket s = new Socket("talk.google.com", 5222);
PrintWriter out = new PrintWriter(s.getOutputStream());
out.println("<?xml version=\\'1.0\\' encoding=\\'utf-8\\' ?>");
out
.println("<stream:stream to='talk.google.com:5222' "
+ "xmlns='jabber:client'"
+ " xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>");
out.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(s
.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
out.println("</stream>");
s.close();
} catch (SSLPeerUnverifiedException e) {
System.out.println(" Erreur d'auth :" + e.getLocalizedMessage());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
}
}
}
How can i connect to the gtalk server?
XMPP isn't a trivial protocol to implement, and I don't think you'll get very far by sending hand-crafted XML strings to the server.
I'd recommend studying some existing source code.
Spark and OpenFire are one example of a nice open source XMPP client and server implementation in java.
You might try getting OpenFire running locally in a debugger (or with verbose logging turned on) so you can get an idea of what it's doing with your packets.
Although not directly related, you may need a server to test against and one for which you can see the source. I suggest that you look at what the Vysper guys are doing http://mina.apache.org/vysper/
You have several problems with your code, not counting the stylistic one of not using a DOM before sending (which is a best practice in the XMPP world).
You need to connect to "talk.l.google.com". See the results of "dig +short _xmpp-client._tcp.gmail.com SRV" on the command line to find out what servers to connect to.
In your XML prolog, you're double escaping the single quotes, which will actually send a backslash.
The to attribute in your stream:stream should be "gmail.com", without the port number.
All of that being said, I'll second the other posters with a plea for you to not start another Java client library, but to pitch in on an existing one.
Why are you writing an XML version before writing the stream stanza? The server is expecting a stream of defined format, and not an XML structure. Remove this line
"out.println("< ? xml version=\\'1.0\\' encoding=\\'utf-8\\' ?>")"
then it will work for sure.