I'm tried to get AS400 TCP Connection Status. but i'm failed :( can anyone help me to do this. i'm new to JT400 java development. please help me friends.
i want to get IP address of a job
i want to get TCP Connection Status using that (1) IP address.
Please help me
Thank you!
Edit :
i got this class
com.ibm.as400.util.commtrace.TCPHeader
It's return this informations
getACKFlag()
getAckNum()
getCheckSum()
getCWRFlag()
getDataOffset()
getDstPort() ..etc
now i want to get this informations. its mean, how to get TCP status using this class.
Please help me
Thank You
To get the IP address of a job:
System.out.println("IP address " + job.getValue(job.CLIENT_IP_ADDRESS));
The commtrace classes are not real-time. They use a trace file which was created on the IBM i server at some earlier time. In order to create that trace file, see the Javadoc for com.ibm.as400.util.commtrace.CommTrace Basically you will need to run the IBM i commands STRCMNTRC, ENDCMNTRC and DMPCMNTRC. Then use commtrace.CommTrace to create a trace file formatted so that the other commtrace classes can read it.
EDIT: Add code snippet from commtrace.Format Javadoc
import java.util.*;
import com.ibm.as400.access.*;
import com.ibm.as400.util.commtrace.*;
public class TestCommTrace {
public static void main(String[] args) {
try {
Format f = new Format("/buck/linetrace");
FormatProperties fmtprop = new FormatProperties();
f.setFilterProperties(fmtprop); // Sets the filtering properties for this Format
f.formatProlog(); // Format the prolog
Prolog pro = f.getProlog();
System.out.println(pro.toString());
if(!pro.invalidData()) { // This is not a valid trace
Frame rec;
while((rec=f.getNextRecord())!=null) { // Get the records
System.out.print("Frame " + rec.getRecNum().toString()); // Print out the Frame Number
System.out.println(" time " + rec.getTime().toString()); // Print out the time
IPPacket p = rec.getPacket(); // Get this records packet
Header h = p.getHeader(); // Get the first header
if(p.getType()==IPPacket.IP4) { // If IP4 IPPacket
if(h.getType()==Header.IP4) { // If IP4 Header
IP4Header ip4 = (IP4Header) h; // Cast to IP4 so we can access methods
System.out.println(h.getName()); // Print the name
System.out.println("IP4 src:"+ip4.getSrcAddr() + " dst:" + ip4.getDstAddr());
System.out.println(ip4.printHexHeader()); // Print the header as hex
// Print a string representation of the header.
System.out.println(ip4.toString()); // hex string
//System.out.println(ip4.toString(fmtprop)); // very detailed
while((h=h.getNextHeader())!=null) { // Get the rest of the headers
if(h.getType()==Header.TCP) { // If its a TCP header
TCPHeader tcp = (TCPHeader) h; // Cast so we can access methods
System.out.println("TCP src:" + tcp.getSrcPort() + " dst:" + tcp.getDstPort() + " checksum:" + tcp.getCheckSum());
System.out.println(tcp.toString()); // hex string
//System.out.println(tcp.toString(fmtprop)); // very detailed
} else if(h.getType()==Header.UDP) { // If its a UDP header
UDPHeader udp = (UDPHeader) h; // Cast so we can access methods
System.out.println("UDP src:" + udp.getSrcPort() + " dst:" + udp.getDstPort());
System.out.println(udp.toString());
}
}
}
}
}
f.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
EDIT: Some more detailed information
1) On the IBM system, someone with special permission must run STRCMNTRC and collect communications trace information. This trace file contains all of the TCP packets that flowed between the IBM system and the outside world. For example, if the trace runs for an hour, it will collect every packet the system sent and received during that hour. The trace data is stored in a format that is special and can not be directly read.
2) To make the trace data readable, use the DMPCMNTRC command. This will create a flat text stream file out of the trace data. This data needs to get to your PC so that the com.ibm.as400.util.commtrace classes can work on it.
3) On your PC, run com.ibm.as400.util.commtrace.CommTrace. This will create a file in a simple text form that com.ibm.as400.util.commtrace can process. I put mine in /buck/linetrace. It is important to understand that there are hundreds or thousands of packets in this log, and every one of them has the information you ask about in the question. There is not one single ACK flag, there are many hundreds of them. In order to understand what is happening, your program will need to read a packet, get the header, then the status, get the data and then read the next packet, and the next and the next, all the way through them all.
4) In order to filter by IP address, you can either use setFilterProperties() or have your code check the IP addresses in each packet header and only process the headers you want to.
It is important to understand that the 'status' you are looking for is not a property of an IP address, it is a property of a TCP packet. There is no way to ask the system for the ACK flag of an IP address because there is no such property to be returned. The only way to get these things is to record them at the instant the packet is read or written by the system.
I would be very surprised if you really need these flags; almost no one does. Usually, 'connection status' means a way to determine if the machine is running or not. ping is the typical way to answer that question, but not all machines will answer a ping. For those machines, the best way is to try to connect to the machine and port you want to test.
Related
I'm trying to create communication between simple Java App (using java.net.http.WebSocket class) and remote google-chrome run using google-chrome --remote-debugging-port=9222 --user-data-dir=.
Sending and receiving small messages works as expected, but there is an issue in case of bigger messages, 16kb.
Here is part of java source:
var uri = new URI("ws://127.0.0.1:9222/devtools/page/C0D7B4DBC53FB39F7A4BE51DA79E96BB");
/// create websocket client
WebSocket ws = HttpClient
.newHttpClient()
.newWebSocketBuilder()
.connectTimeout(Duration.ofSeconds(30))
.buildAsync(uri, simpleListener)
.join();
// session Id attached to chrome tab
String sessionId = "...";
// send message
String message = "{\"id\":1,\"method\":\"Runtime.evaluate\",\"params\":{\"expression\":\"document.body.style.backgroundColor = 'blue';\",\"returnByValue\":true,\"awaitPromise\":true,\"userGesture\":true},\"sessionId\":\"" + sessionId + "\"}";
// this works
ws.send(message, true);
// generate big string contains over 18k chars for testing purpose
String bigMessage = "{\"id\":2,\"method\":\"Runtime.evaluate\",\"params\":{\"expression\":\"[" + ("1,".repeat(9000)) + "1]\",\"returnByValue\":true,\"awaitPromise\":true,\"userGesture\":true},\"sessionId\":\"" + sessionId + "\"}";
// this doesn't work
ws.send(bigMessage, true);
Here is stack:
java.net.SocketException: Connection reset
at java.base/sun.nio.ch.SocketChannelImpl.throwConnectionReset(SocketChannelImpl.java:345)
at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:376)
at java.net.http/jdk.internal.net.http.SocketTube.readAvailable(SocketTube.java:1153)
at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription.read(SocketTube.java:821)
at java.net.http/jdk.internal.net.http.SocketTube$SocketFlowTask.run(SocketTube.java:175)
at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:198)
...
I've tried basically the same by using puppeteer (nodejs library) and it works as expected.
I can't find any resource online about this issue.
Is there anything I'm missing in my example?
Here is url to simple example:
https://github.com/zeljic/websocket-devtools-protocol
Based on what I've seen so far, my best guess would be that Chrome Dev Tools do not process fragmented Text messages on that exposed webSocketDebuggerUrl endpoint. Whether Chrome Dev Tools can be configured to do so or not, is another question. I must note, however, that RFC 6455 (The WebSocket Protocol) mandates it:
Clients and servers MUST support receiving both fragmented and unfragmented messages.
There's one workaround I can see here. Keep in mind that this is unsupported and may change in the future unexpectedly. When running your client, specify the following system property on the command line -Djdk.httpclient.websocket.intermediateBufferSize=1048576 (or pick any other suitable size). As long as you keep sending your messages with true passed as boolean last argument to the send* methods, java.net.http.WebSocket will send messages unfragment, in a single WebSocket frame.
Well I had a similar issue when sending a big string by using web-sockets in java with a tomcat server.
There can be payload limit to send or receive in websocket server .
checkout org.apache.tomcat.websocket.textBufferSize in tomcat's doc. By default it is 8192 bytes try increasing the size.
I am attempting to create a simple users online but cant seem to get the String vector to update properly.
Client Code: (Both vectors are global)
else if(command.equals("GET USER LIST")){
test = (Vector)ois.readObject();
for(String s: test){
if(!usersConnected.contains(s)){
usersConnected.add(s);
jlConnUsers.setText(jlConnUsers.getText() + s + " ");
}
}
System.out.println("Test array " + test);
System.out.println("User array " + usersConnected);
}
Server Code:
public void getActiveUserList(){
for(ClientConnection client: activeConnections){
String user = client.getUserName();
if(!activeUserList.contains(user)){
activeUserList.add(user);
}
System.out.println("sent TO client FULL USER LIST:" + activeUserList);
}
}
So, client connects, hits a button "Get user list" which gets sent to the server, server goes through hashmap, adds all current client names to a vector and sends it back...
My issue: If I connect one client and get the user list, it will display the SINGLE name properly. If I connect two clients and attempt to get the user list, client 1 will not receive the updated vector EVEN THOUGH the server is sending the correct vector.
The Server always sends the correct vector with the correct user names.
Client 1: Name 1 (Will not update after more clients connect)
Client 2: Name 1, Name 2 (Will not update after more clients connect)
Client 3: Name 1, Name 2, Name 3 (Will not update after more clients connect)
If I access the getusers BEFORE another client connects, I can not get the correct vector again.
Im fairly certain im missing something extremely small here, I could be wrong. Any ideas? Thanks!
I believe this has been solved. REFERENCES to the vector were being passed instead of the new vector.
Calling the "reset" method prior to sending over the object seems to have fixed this.
In my Java application I am using 2 network connections to a webserver. I ask for a range of data for a file from each interface with a GET message and when I get the data, I calc how much time it took and the bps for each link.
This part works fine.
(I haven't closed the sockets yet)
I determine which link is faster then "attempt" to send another HTTP GET request for the rest of the file on the faster link. This is where my problem is, The 2nd cOut.write(GET) doesn't send anything and hence I get no data back.
Do I have to close the socket and re-establish my connection before I can write to it again?
edit
OK to answer some Qs:
Yes TCP
The following code (used on the low speed link) is used first to grab the first block of data using the GET request:
GET /test-downloads/10mb.txt HTTP/1.1
HOST: www.cse.usf.edu
Range: bytes=0-999999
Connection: Close
Is the Connection: Close what is doing it? as when I use Keep-Alive I get a 5sec delay and still do not send/receive data on a subsequent write/read.
// This try block has another fo rthe other link but uses [1]
try {
skSocket[0] = new Socket( ipServer, 80, InetAddress.getByName(ipLowLink), 0 );
skSocket[0].setTcpNoDelay(true);
skSocket[0].setKeepAlive(true);
cOut[0] = new PrintWriter(skSocket[0].getOutputStream(),true);
cIn[0] = new InputStreamReader(skSocket[0].getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/* -----------------------------------
the following code is what is called
once for each link (ie cOut[0], cOut [1])
then after determining which has the better bps
(using a GET to grab the rest of the file)
this code is repeated on the designated link
----------------------------------- */
// Make GET header
GET.append(o.strGetRange(ipServer, File, startRange, endRange-1));
// send GET for a specific range of data
cOut[0].print(GET);
cOut[0].flush();
try {
char[] buffer = new char[4*1024];
int n = 0;
while (n >= 0) {
try {
n = cIn[0].read(buffer, 0, buffer.length);
} catch (IOException e) {
e.printStackTrace();
}
if (n > 0) {
raw[0].append(buffer, 0, n); // raw is a stringBuffer
}
}
}
finally {
//if (b != null) b.close();
}
I use the same code as above for my 2nd link (just shift the start/end range over a block) and after I determine the bps, I request the remaining data on the best link (don't worry about how big the file is, etc, I have all that logic done and not the point of the problem)
Now for my subsequent request for the rest of the data, I use the same code as above minus the socket/in/out creation. But the write doesn't send anything. (I hav done the socket check isClosed(), isConnected(), isBound(), isInputShutdown(), isOutboundShutdown(), and all prove that the socket is still open/useable.
According to the HTTP 1.1 spec, section 8:
An HTTP/1.1 client MAY expect a connection to remain open, but would decide to keep it open based on whether the response from a server contains a Connection header with the connection-token close. In case the client does not want to maintain a connection for more than that request, it SHOULD send a Connection header including the connection-token close.
So, you should ensure that you are using HTTP 1.1, and if you are, you should also check that your webserver supports persistent connections (it probably does). However, bear in mind that the spec says SHOULD and not MUST and so this functionality could be considered optional for some servers.
As per the excerpt above, check for a connection header with the connection-close token.
Without a SSCCE, it's going to be difficult to give any concrete recommendations.
I'm having a socket problem. This problem occurs when I'm running the server and client on the same PC i.e. using "localhost" parameter. But problem is not seen when different PCs are being used.
Client sends a file with these codes:
output_local.write(buffer, 0, bytesRead);
output_local.flush();
And after that in another method I'm sending a command with these:
outputStream.write(string);
outputStream.flush();
Server appends the command to the end of the file. So it thinks it hasn't received the command from the client yet. do you have an idea what might causing this problem? How can I solve the defect? below is the file receive method at the server:
while (true) {
try {
bytesReceived = input.read(buffer);
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("exception occured");
break;
}
System.out.println("received:" + bytesReceived);
try {
/* Write to the file */
wr.write(buffer, 0, bytesReceived);
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
total_byte = total_byte + bytesReceived;
if (total_byte >= filesizeInt) {
break;
}
}
If you want message-like support, you need a create a protocol to clarify what you're going to send and receive.
In TCP, you can't rely on separate "packets" being received separately (e.g., sending 4 chunks of 10 bytes may be received as 1 chunk of 40, or of 2 chunks of 20, or one chunk of 39 and one chunk of 1). TCP guarantees in order delivery, but not any particular 'packetization' of your data.
So, for example, if you're sending a string you need to first send the string length then its bytes. The logic in pseudocode would be something like:
Client:
Send the command indicator
Send the payload length
Send the payload
Server:
Read the command indicator
Read the payload length
Loop reading payload until the complete length has been read
The defect is that you're treating a stream-based protocol (TCP) as if it were a message-oriented protocol. It's not. You should assume that this can happen.
If you need to break your stream into individual messages, you should use either delimiters or (preferably IMO) a length prefix for each message. You should also then anticipate that any read you issue may not receive as much data as you've asked for - in other words, not only can messages be combined if you're not careful, but they can easily be split.
I mentioned that I prefer length-prefixing to delimiters. Pros and cons:
The benefit of using a message delimiter is that you don't need to know the message size before you start sending.
The benefits of using a length prefix are:
The code for reading the message doesn't need to care about the data within the message at all - it only needs to know how long it is. You read the message length, you read the message data (looping round until you've read it all) and then you pass the message on for process. Simple.
You don't need to worry about "escaping" the delimiter if you want it to appear within a normal message.
As TCP is a stream oriented connection, this behaviour is normal if the writer writes faster than the reader reads, or than the TCP stack sends packets.
You should add a separator to separate the parts of the streams, e.g. by using a length field for sub packets, or by using separators such as newline (\n, char code 10).
Another option could be to use UDP (or even SCTP), but that depends on the task to be fulfilled.
A while ago I developed a little LAN chat app. in Java which allows chatting with other hosts, send images, etc. Although it was created just for fun, now it's being used where I work.
Currently, there is no "chat server" on the app. where each client registers, updates it's status, etc. (I liked the idea of symmetric design and not depending on a server running on some other machine).
Instead, each host is a client/server which has a hosts.properties file with the hostname of the other hosts, and - for instance - broadcasts to each one of them when sending a massive message/image/whatever.
In the beginning there were just a couple of hosts, so this hosts.properties file wasn't an issue. But as the amount of users increased, the need of updating that file was a bit daunting. So now I've decided to get rid of it, and each time the app. starts, dynammically find the other active hosts.
However, I cannot find the correct way of implement this. I've tried starting different threads, each one of them searching for other hosts in a known range of IP addresses. Something like this (simplified for the sake of readability):
/** HostsLocator */
public static void searchForHosts(boolean waitToEnd) {
for (int i=0; i < MAX_IP; i+= MAX_IP / threads) {
HostsLocator detector = new HostsLocator(i, i+(MAX_IP / threads - 1)); // range: from - to
new Thread(detector).start();
}
}
public void run() {
for (int i=from; i<=to; i++)
findHosts( maskAddress + Integer.toString(i) );
}
public static boolean findHosts(String IP) {
InetAddress address = InetAddress.getByName(IP);
if ( address.isReachable(CONNECTION_TIME_OUT) )
// host found!
}
However:
With a single thread and a low value in CONNECTION_TIME_OUT (500ms) I get wrong Host Not Found status for for hosts actually active.
With a high value in CONNECTION_TIME_OUT (5000ms) and only one single thread takes forever to end
With several threads I've also found problems similar like the first one, due to collisions.
So... I guess there's a better way of solving this problem but I couldn't find it. Any advice? Thanks!
You could try UDP Broadcast to a specific port. All running instances of your app on the network could listen to that port and then respond with a message identifying them as a host.
You could do this a lot easier using UDP. Check this tutorial for examples.
Use Bonjour/Zeroconf.
The jmdns project has all you need.
For finding all hosts in lan in java execute commands from java and add the result to JList
Here is the small code that will help to you to read all hosts in lan in windows there will be other commands for other os take look at the following code
try {
Runtime rt = Runtime.getRuntime();
FileWriter write=new FileWriter("mylist.txt");
BufferedWriter writer=new BufferedWriter(write);
Process pr = rt.exec("net view");
BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line=null;
String hosts="";
while((line=input.readLine()) != null) {
Thread.sleep(100);
if((!(line.equals("")))&&(!(line.equalsIgnoreCase("Server Name Remark")))&&(!(line.equalsIgnoreCase("-------------------------------------------------------------------------------")))&&(!(line.equalsIgnoreCase("The command completed successfully."))))
{
line=line.replace('\\',' ');
line=line.trim();
listModel.addElement(line);
hosts=hosts+line.trim()+",";
hosts=hosts.trim();
}
}
writer.write(hosts);
writer.close();
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
Each host keeps track of all the hosts they have met. When you shut down, save the known hosts to file and reuse the next time you start up.
Every so many minutes, send each of the known hosts a list of all known hosts.
That way
a) No network scanning
b) A new host will spread around the network
Then when a new host joins, he just needs to know 1 other host to learn about everyone.
A host that isn't seen for a week, or is seen from a new IP is dropped from the list of updated.
You could attempt to use DNS service discovery
There seems to be a project on sourceforge (that I have not looked at, beyond doing a cursory search...)