I'm coding a little program that checks an online store for new items in a specific department. When it does find that a new item has been added, it's supposed to send that info to a simple IRC-bot, which in turn writes it out in a channel so I can see it immediately.
The problem is that the IRC part only works once. So while the parser successfully announce every new item at the store in my console, the IRC bot only shows the first. So the problem is most likely my socket code.
I shall tell you that I'm a complete noob with sockets, so it can be a really simple problem(for you, that is).
Enough talk, here's the relevant code:
The bot:
public void openSocket() throws IOException{
serversock = new ServerSocket(1551);
Socket sock = serversock.accept();
BufferedReader incoming = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String inString = incoming.readLine();
sendMessage("#channel", inString);
}
public static void main(String[] args) throws Exception {
XanaduBot bot = new XanaduBot();
bot.setVerbose(true);
bot.connect("irc.server.net");
bot.joinChannel("#channel");
bot.openSocket();
}
And the socket part on the scraper:
if(old == false){
Socket client = new Socket("localhost",1551);
DataOutputStream toBot = new DataOutputStream(client.getOutputStream());
String infoToSend = "New product! "+ info;
toBot.writeBytes(infoToSend + '\n');
toBot.flush();
System.out.println(infoToSend);
}
The variable old is false whenever the program finds a new item. And I know that exceptions are handled pretty bad here, sorry for that!
Any help appreciated!
Related
I want to have Server - Client relation. Once client gets connected to a server, server sends a message to a client every 1.5 seconds. Server doesn't do anything with messages from client for simplicity. In client's code, I want to use System.in to send messages to server (which don't mean anything) and when I send it, I want to read server's response (all accumulated messages from server). Code is not a snippet, but "real code".
Client:
public class ClientClass {
public static final String IP_ADDRESS = "127.0.0.1";
public static final int PORT = 9090;
public static void main (String[] args) throws IOException {
Socket socket = new Socket (IP_ADDRESS,PORT);
PrintWriter output = new PrintWriter (socket.getOutputStream (),true);
BufferedReader input = new BufferedReader (new InputStreamReader (socket.getInputStream ()));
BufferedReader keyboard = new BufferedReader (new InputStreamReader (System.in));
while (true){
System.out.println ("Enter message you want to send to server:");
String msg = keyboard.readLine ();
output.println (msg);
String serverResponses = input.readLine ();
while (serverResponses!=null){
System.out.println (serverResponses);
serverResponses=input.readLine ();
}
}
}
}
Server:
public class ServerClass {
public static int PORT = 9090;
public static void main (String[] args) throws IOException, InterruptedException {
ServerSocket server = new ServerSocket (PORT);
Socket client = server.accept ();
PrintWriter output = new PrintWriter (client.getOutputStream (),true);
while (true){
output.println ("hello from server");
Thread.sleep (1500);
}
}
}
//My comment: readLine() method in client is blocking, so I can't read server's messages until I actually read something from keyboard. That is why I have loop to "pick up" all lines from inputStream. I expect that once I read all the lines, variable stringResponses gets null and breaks from inner while loop. Then I thought that I would get a print to console of "enter message you want to send to server" found in outer loop. Unfortunately, my code never breaks out from inner while loop and I want to know why. How is it never null, when I am writing to a stream every 1.5s, meaning there is plenty of time for it to be null and break from loop.
ACTUAL OUTPUT:
Enter message you want to send to server:
hey! //this is what I typed
hello from server
hello from server
hello from server
//these three popped immediately, as they accumulated.
hello from server
hello from server
hello from server
hello from server
//keeps printing "hello from server" every 1.5s and never comes back to "enter your message" -WHY?
readLine returns null at the end of stream. Since the Server Socket isn't closed. It is never null in your inner loop.
Link - https://docs.oracle.com/javase/7/docs/api/java/io/BufferedReader.html#readLine()
A String containing the contents of the line, not including any
line-termination characters, or null if the end of the stream has been
reached
What do you expect the behaviour when readLine got invoked in a loop on your keyboard object ?
String msg = keyboard.readLine();
while(msg != null)
msg = keyboard.readLine();
This too will keep on taking inputs from the System.in. The loop would never end.
Solutions
As quoted above from java documentation, readLine method blocks for an input. That is the reason, there is no effect of delaying server response. The method returns null only at the end of the stream.
Solution 1 - Making use of ready method
ready method returns false when the read methods has to wait for an input data. As the Server code is sleeping for 1.5 sec, this method should return false during that time.
The downside of this approach is that if Server is not finished with all the response lines on time, then the inner loop where you collect all Server Responses will break.
while (true){
System.out.println ("Enter message you want to send to server:");
String msg = keyboard.readLine ();
output.println (msg);
String serverResponses = input.readLine ();
System.out.println (serverResponses);
while (input.ready()){
serverResponses=input.readLine ();
System.out.println (serverResponses);
}
}
Solution 2 - Server sends total lines
If the server knows about the total number of lines, then that can be sent as the first line in the stream. Depending upon total lines, client code can read those many lines. The downside of this approach is that an extra line has to be added in the Server response.
while (true){
System.out.println ("Enter message you want to send to server:");
String msg = keyboard.readLine ();
output.println (msg);
Integer linesCount = Integer.parseInt(input.readLine ());
for (int i=0; i< linesCount; i++){
String serverResponses=input.readLine ();
System.out.println (serverResponses);
}
}
I'm learning distributed systems basics and currently I'm trying to do a simple yet realistic messenger between one server and one client. What I do intend is that on each endpoint socket side (Server and Client) text automatically updates (like a real "messaging app"). In other words, I want that the moment I write and "send" the message, it automatically appears on recipient side. What I have now follows this schema:
I send a message (let's assume from client)
To see that message on Server's side I need to reply first (because Server's BufferedReader / Client's PrintWriter is only read after asking for the answer)
My code:
public class ClientSide {
public static void main(String [] args){
String host_name = args[0];
int port_number = Integer.parseInt(args[1]);
try {
Socket s = new Socket(host_name, port_number);
PrintWriter out =
new PrintWriter(s.getOutputStream(), true);
BufferedReader in =
new BufferedReader(
new InputStreamReader(s.getInputStream()));
BufferedReader stdIn =
new BufferedReader(
new InputStreamReader(System.in));
String answer;
while ((answer = stdIn.readLine()) != null) {
out.println(answer);
System.out.println("\nlocalhost said\n\t" + in.readLine());
}
} catch (IOException ex) {
Logger.getLogger(ClientSide.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class ServerSide {
public static void main(String [] args){
int port_number = Integer.parseInt(args[0]);
try {
ServerSocket ss = new ServerSocket(port_number);
Socket tcp = ss.accept();
PrintWriter out =
new PrintWriter(tcp.getOutputStream(), true);
BufferedReader in =
new BufferedReader(
new InputStreamReader(tcp.getInputStream()));
BufferedReader stdIn =
new BufferedReader(
new InputStreamReader(System.in));
String answer;
while ((answer = stdIn.readLine()) != null){
out.println(answer);
System.out.println("\nClient said\n\t" + in.readLine());
}
} catch (IOException ex) {
Logger.getLogger(ServerSide.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
How can I do this? Does it involve advanced knowledge on the matter?
Thanks in advance.
The core problem is that you want to wait for two events concurrently -- either a message from the socket, or input from the user!
You want to wait on both at the same time -- you don't want to be stuck waiting for a message in the socket if the user types a message; nor to be waiting for the user message while you have a new message from the network.
To 'wait' for messages from multiple streams, you have java.nio. I believe it is the most correct way of doing it.
But if you want to keep using the BufferedReader, there is a ready() method that returns true if and only if there is a message waiting to be read.
Your code after the in and stdIn declarations would then look something like (I didn't test it!!):
while(true) {
if(stdIn.ready()) {
System.out.println("I said " + stdIn.readLine());
}
if(in.ready()) (
System.out.println("He said " + in.readLine());
}
}
A few somewhat useful random links:
Java - Reading from a buffered reader (from a socket) is pausing the thread
Is there epoll equivalent in Java?
I tried to make a console chat server. the main problem i am facing is that i can not send the message to the server.. as you can see in the img i uploaded that the server and the client are connected. but when i type anything in the client side. The client becomes unresponsive and i have to close the cmd prompt.
How can i fix this?
Is something wrong with my computer or is the code wrong?
public class MyClient
{
Socket s ;
DataInputStream din ;
DataOutputStream dout;
public MyClient()
{
try
{
s= new Socket("localhost",10);
System.out.println(s);
din = new DataInputStream(s.getInputStream());
dout= new DataOutputStream(s.getOutputStream());
ClientChat();
}
catch(Exception e)
{
System.err.println(e);
}
}
public void ClientChat() throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//Scanner s2 = new Scanner(System.in);
String s1;
System.out.println("start the conversation");
do
{
s1=br.readLine();
//s1=s2.nextLine();
dout.flush();
System.out.println("server:"+din.readUTF());
}
while(!s1.equals("stop"));
}
public static void main (String args[])
{
new MyClient();
}
}
The code snippet never calls dout.write*(), so nothing is ever sent over the Socket.
readLine() will block until a line of text is read, so messages sent to the client won't be printed until after the client types a 2nd line of text. You can fix this either by using asynchronous I/O or by moving the read loop into it's own Thread.
You need to make the server and client a thread, so they can work independently.
server as thread will wait for a client connections and will receive messages.
client as thread will work on its own.
problem is that they cannot run concurrently.
Use dout.writeUTF(s1); inside the do loop.
The writeUTF will allow you to write the subsequent message till then It will be stuck at readutf function.
The java.io.DataOuputStream.writeUTF(String str) method writes a string to the underlying output stream using modified UTF-8 encoding. Refer to this
I am having an issue with the response I am getting when I try to get the authorization code I need to start the authenticated client. The response appears (at least to me) to be some sort of binary data, (with one or two recognizable string fragments in it), but I have no idea how to deal with it. The code from the API's 'hello world' program seems to be parsing this data as a string, but when I try it, it fails because it isn't in the expected format.
This is adapted from the 'Hello World' program (from the box api github wiki) found here in order to show what the problem appears to be.
import java.awt.Desktop;
import java.io.*;
import java.net.*;
public class HelloBox {
public static final int socket_port = 4000;
public static final String
redirect_uri = "https://localhost:" + socket_port,
client_id = /* [...] */, client_secret = /* [...] */;
public static void main(String[] args) throws Exception{
Desktop.getDesktop().browse(URI.create(
"https://www.box.com/api/oauth2/authorize?" +
"response_type=code" +
"&client_id=" + client_id +
"&redirect_uri=" + redirect_uri));
ServerSocket serverSocket = new ServerSocket(socket_port);
Socket socket = serverSocket.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(new FileWriter("output.txt"));
for(int idx = 0; idx < 4; idx++){
String line = in.readLine();
System.out.println(line);
out.println(line);
}
//[... closing all the streams and sockets ...]
}
}
All the lines after the fourth are just null, so that is why I stopped it after four lines.
You can see the result in my output.txt file here. My computer refuses to paste the string, so I couldn't include it itself in the question. I have tried examining the output with a hex editor, but I couldn't see any obvious pattern to it. (Bursts of stuff separated by occasional NULL?)
Myriad Google searches turned up nothing that appears to be of relevance for this issue, and neither the Javadoc nor the API tutorials were helpful here, either.
How can I deal with this issue? If my code is wrong, please tell me how I can correct it.
EDIT:
So I tried replacing the socket and serverSocket with
SSLServerSocket serverSocket = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(socket_port);
SSLSocket socket = (SSLSocket) serverSocket.accept();
but now I am getting
javax.net.ssl.SSLHandshakeException: no cipher suites in common at the line where it first tries to read from the stream.
First of all, this is a homework problem. That being said, I'm stuck. Googling for java Properties over Sockets results in a lot of irrelevant things.
I'm trying to transfer a Properties object over a socket. The API says it can be done with a Stream or a Writer/Reader, but I can't get it to work. I can do it manually, that is, if I read the file line by line and pass it through a PrintWriter.
On the client side I've got roughly:
socket = new Socket(host, port);
outStream = socket.getOutputStream();
out = new PrintWriter(outStream, true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
reader = new BufferedReader(new FileReader(file));
...
props.load(reader);
props.store(out, null);
On the server side the receiving bits look like:
out = new PrintWriter(sock.getOutputStream(), true);
inStream = sock.getInputStream();
in = new BufferedReader( new InputStreamReader(inStream));
...
props.load(in); // hangs
// doesn't get to code here...
In this case it hangs at the props.load(in). Instead of doing props.load(in), I read it in line by line to make sure props.store(out, null) was working, and the data looks like its being transferred.
Is there something about load/store I don't understand, or is it an issue with the Stream/Writer/Reader?
I think this will answer this question as well as How do I recognize EOF in Java Sockets? and What can I send to an InputStream to signify EOF has been reached?
I had a similar problem; my dilemma was that I had a client/server request-response protocol where one of the requests included a stream sent from the client side using clientProps.store(). The corresponding serverProps.load() on the server side never returns because it needs to see the "end-of-file" - which in Java means the client has to close it's stream; resulting in the socket connection closing. The unwanted result was that, not only could I not keep the socket open for indefinite request-response exchanges, I couldn't even keep it open for the server to send its reply.
I hated Java for making me do that, even more because the documentation for Properties.load() says:
The specified stream remains open after this method returns.
That could never happen if it's detecting end-of-file by seeing the stream close!! Anyway, now, I still love Java because it allowed me to use this solution (might not be useful if you have any special encoding or localization of the data you are streaming):
I used this on the client side:
PrintWriter toServer;
Properties clientProps = new Properties();
// ... code to populate the properties and to
// construct toServer from the socket ...
clientProps.store(toServer, null);
toServer.write('\u001A'); // this is an old-school ASCII end-of-file
toServer.flush();
On the server side I extended Reader to detect the 1A and return -1 (so that the serverProps.load() learns about the end-of-file in the normal way (by seeing -1 returned from a call to read()), but below that, the stream and the socket stay open.
BufferedReader fromClient;
Properties serverProps = new Properties();
// ... code to construct fromClient from the socket ...
serverProps.load (new PropReader (fromClient));
/////
private static class PropReader extends Reader {
BufferedReader src;
boolean eof=false;
private PropReader(BufferedReader fromClient) {
super();
src=fromClient;
}
#Override
public int read(char[] cbuf, int off, int len) throws IOException {
int inCount;
if (!eof) {
inCount = src.read(cbuf, off, len);
if (inCount > 0) {
// we read a buffer... look at the end for the EOF that the client used to mark the end of file
if (cbuf[off+inCount-1] == '\u001A') {
--inCount; // don't send eof with the data
eof = true; // next time... we'll return -1
}
}
} else {
inCount = -1;
}
return inCount;
}
#Override
public void close() throws IOException {
src.close();
}