I am opening a socket in jmeter (using groovy in JSR223 Sampler), and storing the message in a jmeter variable. This is the below code:
SocketAddress inetSocketAddress = new InetSocketAddress(InetAddress.getByName("localhost"),4801);
def server = new ServerSocket()
server.bind(inetSocketAddress)
while(!vars.get("caseId"))) {
server.accept { socket ->
log.info('Someone is connected')
socket.withStreams { input, output ->
InputStreamReader isReader = new InputStreamReader(input);
BufferedReader reader = new BufferedReader(isReader);
StringBuffer sb = new StringBuffer();
String str;
while((str = reader.readLine())!= null){
sb.append(str);
}
String finalStr = sb.toString()
String caseId = finalStr.split("<caseId>")[1].split("</caseId>")[0]
vars.put("caseId", caseId)
}
log.info("Connection processed")
}
}
if(vars.get("caseId"))
{
try
{
server.close();
vars.put("socketClose",true);
}
catch(Exception e)
{
log.info("Error in closing the socket: " + e.getMessage());
}
}
Now, there is some time delay between the first loop is executed and the message being recieved from the port. It doesnt receive the message immediately, and hence while loop is executed again. And then message is received and it sets caseId. It goes on to close the socket, because caseId is set. And that is throwing the error, because socket is still waiting for the message. So is there a way, to wait until socket has recieved all the messages, so i could properly close it?
Or just force close the socket, and Jmeter wont throw any exception?
Or when i execute next component, say IF controller in Jmeter, it waits until variable socketClose is set true? In that way, instead of while loops inside JSR223 sampler, i could use multiple If Controllers in Jmeter thread.
This is how ServerSocket.close() function works
public void close()
throws IOException
Closes this socket. Any thread currently blocked in accept() will throw a SocketException.
I don't think there is a way "to wait until socket has recieved all the messages" because Socket is dump as a rock and it can either listen for connections or shut down.
Maybe you might be interested in setSoTimeout() function?
Also this line:
vars.put("socketClose",true)
is very suspicious, I think you need to change it either to:
vars.put("socketClose", "true")
or to
vars.putObject("socketClose",true)
as JMeterVariables.put() function can accept only a String, see Top 8 JMeter Java Classes You Should Be Using with Groovy article for more details.
Related
Why can not I read bytes from the TcpClient in C#?
Here is the error I am getting:
Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.
Here is how I start my TcpClient:
public static async void Start()
{
TcpListener server = null;
try
{
server = new TcpListener(IPAddress.Loopback, 13000);
server.Start();
var client = await server.AcceptTcpClientAsync();
var stream = client.GetStream();
var bytes = Convert.FromBase64String("ABCD");
await stream.WriteAsync(bytes, 0, bytes.Length);
client.Close();
}
catch (Exception e)
{
throw;
}
finally
{
if(server != null)
{
server.Stop();
}
}
}
Here is how I run a request to the TcpClient:
try {
var response = (new HttpClient()).GetByteArrayAsync("http://localhost:13000").Result;
return Convert.ToBase64String(response);
} catch(Exception e) {
throw;
}
The return Convert.ToBase64String(response); line is never reached. While I see the quoted above error message inside the Exception e if I hit a breakpoint on the throw line.
Also, during debug the Start() method completes just fine. I.e. it starts, then wait for a request, gets a request, writes to the TclClient and at the end runs the server.Stop(); command.
I am expecting my code to work, because I took it and modified from the official documentation over here.
I tried to check out a few resources which would tackle my exception, but none of them did help.
E.g. I tried to use the question.
First answer tells nothing useful actually, but just plays around with words and at the end states that one can do nothing about the exception (please, correct me if I am missing a point in the answer).
And the second answer tells an impossible in my case problem. Because, I am sure there is nothing running on the 13000 port.
Your client code is using HttpClient, which sends an HTTP request and expects an HTTP response. But your server is not an HTTP server, it is just a plain TCP server, so the client is likely to fail and forcibly close the connection when it doesn't receive a properly formatted HTTP response.
The "official documentation" whose example you modified is not using HttpClient at all, it is using TcpClient instead.
If you want to use HttpClient in your client, then you should use HttpListener instead of TcpListener in your server.
I have a UWP (soon to be MacOS also) application that listens for incoming messages. The user can configure which IP Address and Port to listen on. Once the socket connection is listening, the user can also go back into the settings and change the IP Address or Port. I am trying to figure out how to shut down the existing listener and restart it using the new Port / IP Address when the user changes the values. Here is my code that starts the listener. Any help would be appreciated.
private static Socket iobj_listener;
public async static Task StartListening()
{
try
{
Debug.WriteLine("Point 1");
IPEndPoint localEndPoint = new IPEndPoint(ViewModelObjects.AppSettings.ServerIPAddress, ViewModelObjects.AppSettings.ServerPort);
// Create a TCP/IP socket.
iobj_listener = new Socket(ViewModelObjects.AppSettings.ServerIPAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
iobj_listener.Bind(localEndPoint);
iobj_listener.Listen(100);
ViewModelObjects.AppSettings.ListeningOnSocket = true;
while (true)
{
Debug.WriteLine("Point 2");
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Debug.WriteLine("Waiting for a connection on " + ViewModelObjects.AppSettings.ServerIPAddress.ToString() + "...");
iobj_listener.BeginAccept(
new AsyncCallback(AcceptCallback),
iobj_listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
finally
{
Debug.WriteLine("Point 3");
ViewModelObjects.AppSettings.ListeningOnSocket = false;
}
}
SO I could not find any quick answers so had to kind of figure this out on my own. If you see anything wrong with this, please let me know.
First of all I declared an e_Num as follows
public enum ge_SocketStatus
{
e_NotListening = 0,
e_Listening = 1,
e_Restart = 2
}
Then I added a StopListening function to my class that handles all my Socket communications and set the socket status to not listening as follows:
public static async Task StopListening()
{
try
{
if (iobj_listener.Connected)
{
//Wait till the connection ends or 30 seconds - this is so any last messages can be processed.
await Task.Delay(30000);
}
ViewModelObjects.AppSettings.SocketStatus = ge_SocketStatus.e_NotListening;
iobj_listener.Close(1);
}
catch (Exception ex)
{
App.AppException(ex);
}
}
I then use the value of this enum to know when to end the loop:
public async static Task StartListening()
{
try
{
Debug.WriteLine("Point 1");
IPEndPoint localEndPoint = new IPEndPoint(ViewModelObjects.AppSettings.ServerIPAddress, ViewModelObjects.AppSettings.ServerPort);
// Create a TCP/IP socket.
iobj_listener = new Socket(ViewModelObjects.AppSettings.ServerIPAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
iobj_listener.Bind(localEndPoint);
iobj_listener.Listen(100);
ViewModelObjects.AppSettings.SocketStatus = ge_SocketStatus.e_Listening;
while (ViewModelObjects.AppSettings.SocketStatus == ge_SocketStatus.e_Listening)
{
Debug.WriteLine("Point 2");
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Debug.WriteLine("Waiting for a connection on " + ViewModelObjects.AppSettings.ServerIPAddress.ToString() + "...");
iobj_listener.BeginAccept(
new AsyncCallback(AcceptCallback),
iobj_listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
finally
{
Debug.WriteLine("Point 3");
}
}
This line above
while (ViewModelObjects.AppSettings.SocketStatus == ge_SocketStatus.e_Listening)
used to be
while (true)
so the loop would never end.
One gotcha I found is in the AcceptCallback used in the BeginAccept function of my socket. In this code, I also had to detect if the socket was connected because this function is called one last time after the StartListening loop exits. At the point the socket is not connected so trying to do anything with is, such as EndAccept, causes the application to throw an exception. Below you can see where I added the line
if (listener.Connected)
in order to stop the code from crashing after I had closed the connection.
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
//If we have shut down the socket don't do this.
if (listener.Connected)
{
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
Once all StopListening function ends and everything from the sockets is disconnected, I can call start listening again and open the socket on a different IPAddress and or Port.
I hope this helps as I could not find a good solution to this.
I am trying to implement Facebook X_FACEBOOK_PLATFORM SASL mechanism so I could integrate Facebook Chat to my application over XMPP.
Here is the code:
var ak = "my app id";
var sk = "access token";
var aps = "my app secret";
using (var client = new TcpClient())
{
client.Connect("chat.facebook.com", 5222);
using (var writer = new StreamWriter(client.GetStream())) using (var reader = new StreamReader(client.GetStream()))
{
// Write for the first time
writer.Write("<stream:stream xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\" to=\"chat.facebook.com\"><auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"X-FACEBOOK-PLATFORM\" /></stream:stream>");
writer.Flush();
Thread.Sleep(500);
// I am pretty sure following works or at least it's not what causes the error
var challenge = Encoding.UTF8.GetString(Convert.FromBase64String(XElement.Parse(reader.ReadToEnd()).Elements().Last().Value)).Split('&').Select(s => s.Split('=')).ToDictionary(s => s[0], s => s[1]);
var response = new SortedDictionary<string, string>() { { "api_key", ak }, { "call_id", DateTime.Now.Ticks.ToString() }, { "method", challenge["method"] }, { "nonce", challenge["nonce"] }, { "session_key", sk }, { "v", "1.0" } };
var responseString1 = string.Format("{0}{1}", string.Join(string.Empty, response.Select(p => string.Format("{0}={1}", p.Key, p.Value)).ToArray()), aps);
byte[] hashedResponse1 = null;
using (var prov = new MD5CryptoServiceProvider()) hashedResponse1 = prov.ComputeHash(Encoding.UTF8.GetBytes(responseString1));
var builder = new StringBuilder();
foreach (var item in hashedResponse1) builder.Append(item.ToString("x2"));
var responseString2 = Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format("{0}&sig={1}", string.Join("&", response.Select(p => string.Format("{0}={1}", p.Key, p.Value)).ToArray()), builder.ToString().ToLower()))); ;
// Write for the second time
writer.Write(string.Format("<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">{0}</response>", responseString2));
writer.Flush();
Thread.Sleep(500);
MessageBox.Show(reader.ReadToEnd());
}
}
I shortened and shrunk the code as much as possible, because I think my SASL implementation (whether it works or not, I haven't had a chance to test it yet) is not what causes the error.
I get the following exception thrown at my face: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.
10053
System.Net.Sockets.SocketError.ConnectionAborted
It happens every time I try to read from client's stream for the second time. As you can see i pause a thread here so Facebook server has enough time to answer me, but I used asynchronous approach before and I encountered the exact same thing, so I decided to try it synchronously first. Anyway actual SASL mechanism implementation really shouldn't cause this because if I don't try to authenticate right away, but I send the request to see what mechanisms server uses and select that mechanism in another round of reading and writing, it fails, but when I send mechanism selection XML right away, it works and fails on whatever second I send.
So the conclusion is following: I open the socket connection, write to it, read from it (first read works both sync and async), write to it for the second time and try to read from it for the second time and here it always fails. Clearly then, problem is with socket connection itself. I tried to use new StreamReader for second read but to no avail. This is rather unpleasant since I would really like to implement facade over NetworkStream with "Received" event or something like Send(string data, Action<string> responseProcessor) to get some comfort working with that stream, and I already had the implementation, but it also failed on second read.
Thanks for your suggestions.
Edit: Here is the code of facade over NetworkStream. Same thing happens when using this asynchronous approach, but couple of hours ago it worked, but for second response returned same string as for first. I can't figute out what I changed in a meantime and how.
public void Send(XElement fragment)
{
if (Sent != null) Sent(this, new XmppEventArgs(fragment));
byte[] buffer = new byte[1024];
AsyncCallback callback = null;
callback = (a) =>
{
var available = NetworkStream.EndRead(a);
if (available > 0)
{
StringBuilder.Append(Encoding.UTF8.GetString(buffer, 0, available));
NetworkStream.BeginRead(buffer, 0, buffer.Length, callback, buffer);
}
else
{
var args = new XmppEventArgs(XElement.Parse(StringBuilder.ToString()));
if (Received != null) Received(this, args);
StringBuilder = new StringBuilder();
// NetworkStream.BeginRead(buffer, 0, buffer.Length, callback, buffer);
}
};
NetworkStream.BeginRead(buffer, 0, buffer.Length, callback, buffer);
NetworkStreamWriter.Write(fragment);
NetworkStreamWriter.Flush();
}
The reader.ReadToEnd() call consumes everything until end-of-stream, i.e. until TCP connection is closed.
I'm working with a windows form application in C#. I'm using a socket client which is connecting in an asynchronous way to a server. I would like the socket to try reconnecting immediately to the server if the connection is broken for any reason. Which is the best design to approach the problem? Should I build a thread which is continuously checking if the connection is lost and tries to reconnect to the server?
Here is the code of my XcomClient class which is handling the socket communication:
public void StartConnecting()
{
socketClient.BeginConnect(this.remoteEP, new AsyncCallback(ConnectCallback), this.socketClient);
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
// Signal that the connection has been made.
connectDone.Set();
StartReceiving();
NotifyClientStatusSubscribers(true);
}
catch(Exception e)
{
if (!this.socketClient.Connected)
StartConnecting();
else
{
}
}
}
public void StartReceiving()
{
StateObject state = new StateObject();
state.workSocket = this.socketClient;
socketClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(OnDataReceived), state);
}
private void OnDataReceived(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int iReadBytes = client.EndReceive(ar);
if (iReadBytes > 0)
{
byte[] bytesReceived = new byte[iReadBytes];
Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes);
this.responseList.Enqueue(bytesReceived);
StartReceiving();
receiveDone.Set();
}
else
{
NotifyClientStatusSubscribers(false);
}
}
catch (SocketException e)
{
NotifyClientStatusSubscribers(false);
}
}
Today I try to catch a disconnection by checking the number of bytes received or catching a socket exception.
If your application only receives data on a socket, then in most cases, you will never detect a broken connection. If you don't receive any data for a long time, you don't know if it's because the connection is broken or if the other end simply hasn't sent any data. You will, of course, detect (as EOF on the socket) connections closed by the other end in the normal fashion despite this.
In order to detect a broken connection, you need a keepalive. You need to either:
make the other end guarantee that it will send data on a set schedule, and you time out and close the connection if you don't get it, or,
send a probe to the other end once in a while. In this case the OS will take care of noticing a broken connection and you will get an error reading the socket if it's broken, either promptly (connection reset by peer) or eventually (connection timed out).
Either way, you need a timer. Whether you implement the timer as an event in an event loop or as a thread that sleeps is up to you and the best solution probably depends on how the rest of your application is structured. If you have a main thread that runs an event loop then it's probably best to hook in to that.
You can also enable the TCP keepalives option on the socket, but an application-layer keepalive is generally considered more robust.
I am learning android but I can't get past the InputStream.read().
This is just a socket test - the server sends back two bytes when it receives a connection and I know that this working fine. All I want to do is read these values. The b = data.read reads both values in turn but then hangs, it never returns the -1 value which is what expect it to. Also it does not throw an exception.
Any ideas?
Thanks.
protected void startLongRunningOperation() {
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
Thread t = new Thread() {
public void run() {
try {
Log.d("Socket", "try connect ");
Socket sock = new Socket("192.168.0.12", 5001);
Log.d("socket", "connected");
InputStream data = sock.getInputStream();
int b = 0;
while (b != -1) {
b = data.read();
}
data.close();
} catch (Exception e) {
Log.d("Socket", e.toString());
}
}
};
t.start();
}
Reaching the end of the stream is a special state. It doesn't happen just because there is nothing left to read. If the stream is still open, but there's nothing to be read, it will "hang" (or block) as you've noticed until a byte comes across.
To do what you want, the server either needs to close/end the stream, or you need to use:
while (data.available() > 0) {
..
When the number of available bytes is zero, there's nothing sitting in the stream buffer to be read.
On the other hand, if you know that there should only ever be two bytes to read, and that's the end of your data, then just read the two bytes and move on (i.e. don't use a while loop). The reason to use a while loop here would only be if you weren't sure how many total bytes to expect.