Boost io_service stopping? - sockets

I am working on an NPAPI plugin that allows to use sockets with local inside browsers and I am using Boost sockets for this.
My usage right now is just open the socket write a meesage, read, send a closing message and close and then repeat (I know it is stupid to close and open everytime but I can not change that).
The problem is that after the second open I am unable to read from the socket, until las changes I was able to open write but never got the info back and now it seems the io_service thread is just dying.
I have read a lot of tutorial and info, but no one seems to open several client sockets as I am trying to do.
Here are the class that stores the socket info and handler:
SocketInfo.hpp
class SocketInfo
{
public:
void start_read();
void handle_read(const boost::system::error_code& error, std::size_t bytes_transferred);
FB::JSObjectPtr m_callback;
boost::shared_ptr<boost::asio::ip::tcp::socket> m_socket;
char data_[SOCKETS_API_BUFFER];
int key;
boost::shared_ptr<SocketsAPI> parent;
};
SocketInfo.cpp
void SocketInfo::start_read()
{
parent->log("start_read" + boost::lexical_cast<std::string>(key));
m_socket->async_receive(boost::asio::buffer(data_, SOCKETS_API_BUFFER),
boost::bind(&SocketInfo::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void SocketInfo::handle_read(const boost::system::error_code& error,
std::size_t bytes_transferred)
{
if (!error) {
parent->log("handle_read" + boost::lexical_cast<std::string>(key));
std::string str(&data_[0], &data_[0] + bytes_transferred);
m_callback->InvokeAsync("processData", FB::variant_list_of(str));
start_read();
} else {
parent->log("error closing " + boost::lexical_cast<std::string>(key));
m_callback->InvokeAsync("processCancel", FB::variant_list_of());
parent->do_close(*this);
}
}
SocketApi.h
class SocketsAPI : public FB::JSAPIAuto
{
public:
SocketsAPI(const SocketsPtr& plugin, const FB::BrowserHostPtr& host) :
m_plugin(plugin), m_host(host)
{
... FireBreath code here ...
//Start thread with work
workPtr.reset( new boost::asio::io_service::work(io_service));
ioThreadPtr.reset(new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service)));
}
virtual ~SocketsAPI() {
workPtr.reset();
if (ioThreadPtr) {
ioThreadPtr->join();
}
};
//Socket Methods
int open(const int port, const FB::JSObjectPtr &callback );
void close(const int key);
void write(const int key, const std::string data);
// Method echo
FB::variant echo(const FB::variant& msg);
void do_close(const SocketInfo socket);
void log(const std::string &str);
private:
mapType sockets;
boost::asio::io_service io_service;
boost::shared_ptr<boost::thread> ioThreadPtr;
boost::shared_ptr<boost::asio::io_service::work> workPtr;
void checkOpen(const SocketInfo socket);
void do_write(const std::string data, const SocketInfo socket);
void start_read(const SocketInfo socket);
void empty_handle(const boost::system::error_code& error);
int getFirstEmpty();
SocketInfo getSocket(const int key);
};
SocketAPI.cpp
int SocketsAPI::open(const int port, const FB::JSObjectPtr &callback )
{
log("open");
boost::shared_ptr<SocketInfo> socket;
socket.reset(new SocketInfo);
socket->m_socket.reset(new boost::asio::ip::tcp::socket(io_service));
socket->m_callback = callback;
ip::tcp::endpoint tcp(ip::address::from_string("127.0.0.1"), port);
boost::system::error_code errorcode;
socket->m_socket->connect(tcp, errorcode);
if (errorcode) {
trace("Connection failed: ", errorcode.message());
return -1;
}
log("conenected");
boost::asio::socket_base::keep_alive o(true);
socket->m_socket->set_option(o);
int key = getFirstEmpty();
socket->key = key;
socket->parent.reset(this);
sockets.insert ( std::pair<int,boost::shared_ptr<SocketInfo>>(key,socket));
socket->start_read();
if (io_service.stopped()) {
log("Resetting service");
io_service.reset();
}
return key;
}
void SocketsAPI::close(const int key)
{
SocketInfo socket = getSocket(key);
checkOpen(socket);
log("close");
io_service.post(boost::bind(&SocketsAPI::do_close, this, socket));
}
void SocketsAPI::write(const int key, const std::string data)
{
log("write socket " + boost::lexical_cast<std::string>(key));
SocketInfo socket = getSocket(key);
checkOpen(socket);
io_service.post(boost::bind(&SocketsAPI::do_write, this, Base64::decode(data), socket));
}
void SocketsAPI::checkOpen(const SocketInfo socket)
{
log("checkOpen");
if (!socket.m_socket || !socket.m_socket->is_open()) {
trace("Socket not opened", "");
throw FB::script_error("There is no open socket");
}
}
void SocketsAPI::do_write(const std::string data,
const SocketInfo socket)
{
log("do_write " + boost::lexical_cast<std::string>(socket.key));
if (!socket.m_socket->is_open()) {
return;
}
boost::asio::async_write(*(socket.m_socket.get()),
boost::asio::buffer(&data[0], data.size()),
boost::bind(&SocketsAPI::empty_handle, this, boost::asio::placeholders::error)
);
}
void SocketsAPI::empty_handle(const boost::system::error_code& error)
{
if (error) {
trace("Error writing: ", error.message());
}
}
void SocketsAPI::do_close(const SocketInfo socket)
{
log("do_close");
if (!socket.m_socket || !socket.m_socket->is_open()) {
return;
}
boost::system::error_code errorcode;
socket.m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, errorcode);
if (errorcode) {
trace("Closing failed: ", errorcode.message());
}
socket.m_socket->close(errorcode);
if (errorcode) {
trace("Closing2 failed: ", errorcode.message());
}
mapType::iterator iter = sockets.find(socket.key);
if (iter != sockets.end()) {
sockets.erase (iter);
}
log("do_close end");
}
int SocketsAPI::getFirstEmpty() {
int i = 0;
mapType::iterator iter;
while(true) {
iter = sockets.find(i);
if (iter == sockets.end()) {
return i;
}
i++;
}
}
SocketInfo SocketsAPI::getSocket(const int key) {
mapType::iterator iter = sockets.find(key);
if (iter == sockets.end()) {
trace("Socket not found", "");
throw FB::script_error("Socket not found");
}
log("socket " + boost::lexical_cast<std::string>(key) +" found");
return *iter->second.get();
}
I am sure that something could be improved (please tell me) but I can not find the error why after the second open it just doesn't work.
Traces of excution:
open
conenected
start_read0
write socket 0
socket 0 found
checkOpen
do_write 0
handle_read0
start_read0
write socket 0
socket 0 found
checkOpen
do_write 0
socket 0 found
checkOpen
close
do_close
do_close end
open
conenected
start_read0
write socket 0
socket 0 found
checkOpen
It seems that io_service.run() just stops but the thread is still working and io_service is not stopped so I am not sure what could be happening.

Ok I found the error it was a lot simpler than I thought it just throw an exception and that stop everything but as I was using it inside a browser I didn't notice that.
Still I am unable to solve the problem so you can check: Boost bind object freed on read handler to share some insight.

Related

NodeMCU Unity Connection, using UDP

I am trying to connect NodeMCU with unity for my university project.
My nodemcu receives data (tested with a UDP test tool application). I will leave the code below.
But I have problems with Unity. I tried to find a simple example or something like that.
The code I found recently is simple enough, but it makes Unity freeze. I found it here and edited it a bit.
NodeMCU code in Arduino IDE
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
const char* ssid = "Epic SSID";
const char* password = "EpicPassword";
WiFiUDP Udp;
unsigned int port = 25666;
char packet[255];
IPAddress ip(192, 168, 43, 20);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
void setup()
{
Serial.begin(115200);
Serial.println();
WiFi.hostname("YVRB-01");
WiFi.config(ip, gateway, subnet);
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("Connection Successful");
Udp.begin(port);
Serial.printf("Listener started at IP %s, at port %d", WiFi.localIP().toString().c_str(), port);
}
void loop()
{
int packetSize = Udp.parsePacket();
if (packetSize)
{
Serial.printf("Received %d bytes from %s, port %d", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
int len = Udp.read(packet, 255);
if (len > 0)
{
packet[len] = 0;
}
Serial.printf("UDP packet contents: %s", packet);
Serial.println();
}
Udp.beginPacket (Udp.remoteIP(), Udp.remotePort());
Udp.write("Epic message");
Udp.endPacket();
delay(300);
}
When it worked, I took off my shirt and ran too kitchen.
My code in Unity
/*
C# Network Programming
by Richard Blum
Publisher: Sybex
ISBN: 0782141765
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
public class udpsend : MonoBehaviour
{
Socket server;
IPEndPoint ipep;
void Start()
{
byte[] data = new byte[1024];
ipep = new IPEndPoint(
IPAddress.Parse("192.162.43.209"), 25666);
server = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
string welcome = "I am connected";
data = Encoding.ASCII.GetBytes(welcome);
server.SendTo(data, data.Length, SocketFlags.None, ipep);
}
void Update()
{
string input, stringData;
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)sender;
byte[] data = new byte[1024];
int recv = server.ReceiveFrom(data, ref Remote);
Console.WriteLine("Message received from {0}:", Remote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
//while (true)
//{
// input = Console.ReadLine();
// if (input == "exit")
// break;
// server.SendTo(Encoding.ASCII.GetBytes(input), Remote);
// data = new byte[1024];
// recv = server.ReceiveFrom(data, ref Remote);
// stringData = Encoding.ASCII.GetString(data, 0, recv);
// Console.WriteLine(stringData);
//}
Console.WriteLine("Stopping client");
server.Close();
}
public void SendData(string message)
{
byte[] data = new byte[1024];
data = Encoding.ASCII.GetBytes(message);
server.SendTo(data, data.Length, SocketFlags.None, ipep);
}
}
I'm just saying that I don't fully understand, but I edited a little bit.
Any fixes or code examples will be appreciated. I just want a method that I can call like SendData("Never gonna give you up!").
I can now transfer information from the Unity app to NodeMCU and from NodeMCU to Unity!
All the code is below.
I used the code and edited the a bit.
To receive data, I used this code right here.
To send information, I used this code and like a "mash up" this code together to create one program that can send and receive.
The reason I have done this is that there were a conflict, because there were one client and multiple codes trying to access it.
For Node MCU I used this code which is pretty much the same as I wrote in question above.
I also made manager code using which I can send message and do other stuff.
It is also important to close all the ports or else Unity will freeze (a very annoying thing).
Nodemcu code in the Arduino IDE:
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
const char* ssid = "YVRB";
const char* password = "YGreater";
WiFiUDP Udp;
unsigned int port = 25666;
char packet[255];
IPAddress ip(192, 168, 43, 20);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
void setup()
{
Serial.begin(115200);
Serial.println();
WiFi.hostname("YVRB-01");
WiFi.config(ip, gateway, subnet);
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("Connection Successful");
Udp.begin(port);
Serial.printf("Listener started at IP %s, at port %d", WiFi.localIP().toString().c_str(), port);
Serial.println();
}
void loop()
{
int packetSize = Udp.parsePacket();
if (packetSize)
{
Serial.printf("Received %d bytes from %s, port %d", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
int len = Udp.read(packet, 255);
if (len > 0)
{
packet[len] = 0;
}
Serial.printf("UDP packet contents: %s", packet);
Serial.println();
}
Udp.beginPacket (Udp.remoteIP(), Udp.remotePort());
Udp.write("Important data");
Udp.endPacket();
delay(300);
}
File UDPSend.cs code which receives as well:
// Inspired by this thread: https://forum.unity.com/threads/simple-udp-implementation-send-read-via-mono-c.15900/
// Thanks OP la1n
// Thanks MattijsKneppers for letting me know that I also need to lock my queue while enqueuing
// Adapted during projects according to my needs
using UnityEngine;
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
public class UDPSend
{
public string IP { get; private set; }
public int sourcePort { get; private set; } // Sometimes we need to define the source port, since some devices only accept messages coming from a predefined sourceport.
public int remotePort { get; private set; }
IPEndPoint remoteEndPoint;
Thread receiveThread;
// udpclient object
UdpClient client;
// public
// public string IP = "127.0.0.1"; default local
public int port = 25666; // define > init
// Information
public string lastReceivedUDPPacket = "";
public string allReceivedUDPPackets = ""; // Clean up this from time to time!
public bool newdatahereboys = false;
public void init(string IPAdress, int RemotePort, int SourcePort = -1) // If sourceport is not set, its being chosen randomly by the system
{
IP = IPAdress;
sourcePort = SourcePort;
remotePort = RemotePort;
remoteEndPoint = new IPEndPoint(IPAddress.Parse(IP), remotePort);
if (sourcePort <= -1)
{
client = new UdpClient();
Debug.Log("Sending to " + IP + ": " + remotePort);
}
else
{
client = new UdpClient(sourcePort);
Debug.Log("Sending to " + IP + ": " + remotePort + " from Source Port: " + sourcePort);
}
receiveThread = new Thread(
new ThreadStart(ReceiveData));
receiveThread.IsBackground = true;
receiveThread.Start();
}
private void ReceiveData()
{
//client = sender.client;
while (true)
{
try
{
// Bytes empfangen.
IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
byte[] data = client.Receive(ref anyIP);
// Bytes mit der UTF8-Kodierung in das Textformat kodieren.
string text = Encoding.UTF8.GetString(data);
// Den abgerufenen Text anzeigen.
Debug.Log(text);
newdatahereboys = true;
//PlayerPrefs.SetString("ReceivedData", text);
// Latest UDPpacket
lastReceivedUDPPacket = text;
// ....
allReceivedUDPPackets = allReceivedUDPPackets + text;
}
catch (Exception err)
{
Debug.Log(err.ToString());
}
}
}
// sendData in different ways. Can be extended accordingly
public void sendString(string message)
{
try
{
byte[] data = Encoding.UTF8.GetBytes(message);
client.Send(data, data.Length, remoteEndPoint);
}
catch (Exception err)
{
Debug.Log(err.ToString());
}
}
public void sendInt32(Int32 myInt)
{
try
{
byte[] data = BitConverter.GetBytes(myInt);
client.Send(data, data.Length, remoteEndPoint);
}
catch (Exception err)
{
Debug.Log(err.ToString());
}
}
public void sendInt32Array(Int32[] myInts)
{
try
{
byte[] data = new byte[myInts.Length * sizeof(Int32)];
Buffer.BlockCopy(myInts, 0, data, 0, data.Length);
client.Send(data, data.Length, remoteEndPoint);
}
catch (Exception err)
{
Debug.Log(err.ToString());
}
}
public void sendInt16Array(Int16[] myInts)
{
try
{
byte[] data = new byte[myInts.Length * sizeof(Int16)];
Buffer.BlockCopy(myInts, 0, data, 0, data.Length);
client.Send(data, data.Length, remoteEndPoint);
}
catch (Exception err)
{
Debug.Log(err.ToString());
}
}
public string getLatestUDPPacket()
{
allReceivedUDPPackets = "";
return lastReceivedUDPPacket;
}
public void ClosePorts()
{
Debug.Log("closing receiving UDP on port: " + port);
if (receiveThread != null)
receiveThread.Abort();
client.Close();
}
}
File manager.cs:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class manager : MonoBehaviour {
public int Remoteport = 25666;
public UDPSend sender = new UDPSend();
public string datafromnode;
void Start()
{
sender.init("192.168.43.209", Remoteport, 25666);
sender.sendString("Hello from Start. " + Time.realtimeSinceStartup);
Application.targetFrameRate = 60;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyUp(KeyCode.Return))
sender.sendString("This should be delivered");
if (sender.newdatahereboys)
{
datafromnode = sender.getLatestUDPPacket();
}
}
public void OnDisable()
{
sender.ClosePorts();
}
public void OnApplicationQuit()
{
sender.ClosePorts();
}
}
Success! See justlookatem.

c# How to synchronize socket Asynchronous Receive data from web page

class testDemo
{
public string ResponseContent;
/// <summary>
/// Get the new data and send it out to all other connections.
/// Note: If not data was recieved the connection has probably
/// died.
/// </summary>
/// <param name="ar"></param>
public void OnRecievedData(IAsyncResult ar)
{
// Socket was the passed in object
Socket sock = (Socket)ar.AsyncState;
// Check if we got any data
try
{
int nBytesRec = sock.EndReceive(ar);
if (nBytesRec > 0)
{
ResponseContent += Encoding.UTF8.GetString(m_byBuff, 0, nBytesRec);
SetupRecieveCallback(sock);
}
else
{
// If no data was recieved then the connection is probably dead
//Console.WriteLine("Client {0}, disconnected", sock.RemoteEndPoint);
sock.Shutdown(SocketShutdown.Both);
sock.Close();
}
}
catch (Exception ex)
{
throw new Exception("\n" + sock.RemoteEndPoint.ToString() + ": Remote servr lost!\n" + ex.Message);
}
}
public GetResponse()
{
.....
AsyncCallback onconnect = new AsyncCallback(OnConnect);
var result = socket.BeginConnect(remoteEP, onconnect, socket);
.....
Send();
.....
}
......
public void OnConnect(IAsyncResult ar)
{
// Socket was the passed in object
Socket sock = (Socket)ar.AsyncState;
// Check if we were sucessfull
try
{
if (sock.Connected)
{
SetupRecieveCallback(sock);
}
else
throw new Exception("Unable to connect to remote machine, Connect Failed!");
}
catch (Exception ex)
{
throw new Exception(ex.Message + "Unusual error during Connect!");
}
}
......
public void SetupRecieveCallback(Socket sock)
{
try
{
AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
var result = sock.BeginReceive(m_byBuff, 0, m_byBuff.Length,
SocketFlags.None, recieveData, sock);
bool success = result.AsyncWaitHandle.WaitOne(Timeout * 1000, true);
}
catch (Exception ex)
{
throw new Exception("\n" + sock.RemoteEndPoint.ToString() + ": nSetup Recieve Callback failed!\n" + ex.Message);
}
}
}
class test2
{
class testDemo = new class testDemo();
// below is main, but because testDemo.OnRecievedData is async, so now testDemo.ResponseContent is null,
// i have to use Thread.Sleep(20 * 1000);
Thread.Sleep(20 * 1000); // max time, wait testDdemo done.
string content = testDemo.ResponseContent;
}
One is main thread, one is async thread, the main thread must wait for async thread to done.
I think there will certainly be a better way, how to solve ?
I need a socket web request class, if you have, please help me ..
From China.

Java Socket ArrayList NullPointer Exception

Whenever I run my Chat Server it works until the client connects and then I get a Null Pointer exception at
connections.add(socket);
which crashes it and then this happens every time I run it.
I know my client side is fine because I watched a tutorial a few months ago on how to do this and that server works with my client without crashing
private static ServerSocket server;
private static Socket socket;
private static Scanner input;
private static PrintWriter output;
private static final int port = 444;
private static String message;
private static ArrayList<Socket> connections;
private static Server serverClass;
public Server() {
message = "";
connections = new ArrayList<Socket>();
serverClass = new Server();
}
public void run() {
try {
try {
input = new Scanner(socket.getInputStream());
output = new PrintWriter(socket.getOutputStream());
while(true) {
checkConnection();
if(!input.hasNext()) {
return;
}
message = input.nextLine();
System.out.println("Client said: " + message);
for(int i = 1; i <= connections.size(); i++) {
Socket tempSock = (Socket) connections.get(i - 1);
output.println(message);
output.flush();
}
}
}
finally {
socket.close();
}
}
catch(Exception e) {
System.out.print(e);
}
}
public void checkConnection() throws IOException {
if(!socket.isConnected()) {
for(int i = 1; i <= connections.size(); i++) {
if(connections.get(i) == socket) {
connections.remove(i);
}
}
for(int i = 1; i <= connections.size(); i++) {
Socket disconnectedUser = (Socket) connections.get(i - 1);
System.out.println(disconnectedUser + " has Disconnected!");
}
}
}
public static void main(String[] args) throws IOException{
try {
server = new ServerSocket(port);
System.out.println("Waiting for Clients... ");
while(true) {
socket = server.accept();
connections.add(socket);
System.out.println("Client connected from: " + socket.getLocalAddress().getHostName());
Thread thread = new Thread(serverClass);
thread.start();
}
}
catch(Exception e) {
e.printStackTrace();
}
}
If you get an NPE at connections.add(socket), it can only be because connections is null. Which it is, because you haven't constructed an instance of Server: instead you are trying to execute all its code from main(). The only place you call new Server() from is inside the constructor for Server, which you have clearly never executed at all, as you would have got a StackOverflowError from the infinite recursion.
This code is a real mess:
fix the infinite recursion
construct an instance of Server in your main() method
make connections non-static
make socket a local variable in the accept loop
fix your loops to iterate from 0 to connections.size()-1
and try again.

Asynchronous Client Socket ManualResetEvent holding up execution

I am attempting to utilize MSDN's Asynchronous Client Socket code sample to connect and control some home equipment. As I understand, the sample code's ReceiveCallback method uses an instance of the EventWaitHandle ManualResetEvent and the method receiveDone.WaitOne() to hold processing of the current thread until the thread receives a signal that all of the socket's data has been transmitted from the remote device. After all of the socket's data has been transmitted (the socket's data is empty and bytesRead = 0), the Waithandle is removed and the application continues processing.
Unfortunately, by stepping-through the execution of the code, it appears that after the last time that the client returns data from the remote device, ReceiveCallback never returns to see if the data-queue is empty (i.e. bytesRead = 0), and thus never enters the "else" condition in ReceiveCallback where the state of the ManualResetEvent would have been reset and the application would have continued to process. Thus, since it never enters the "else" condition, ManualResetEvent is never reset and the application freezes.
Although I can remove the "receiveDone.WaitOne()" method from the code - permitting execution without waiting for the ManualResetEvent's notification that all of the data has been received; this returns a data-string from the equipment that is typically incomplete.
Am I using this code sample incorrectly? Has anyone seen this before or had any experience on how to work-around this issue?
7/14/2012 - UPDATE: After further testing of the MSDN's Asynchronous Client Socket Example, it became clear that ReceiveCallback actually re-polls the port and the "bytesRead = 0" condition is satisfied only when the socket is released (i.e. client.Shutdown(SocketShutdown.Both); client.Close(); ). If I understand this correctly, this means that the connection has to be closed to get past the receiveDone.WaitOne() method. If the connection is closed to satisfy the WaitOne() Waithandle, it totally defeats the purpose of the application in that I had been hoping to leave the connection open so that the application could listen for equipment updates, which happen continually.
7/16/2012 - UPDATE: I have written to Microsoft Tech Support who have responded that "We're doing research on this issue. It might take some time before we get back to you." As such, it seems that it doesn't appear that this challenge can be resolved at this time through massaging this code.
Without the availability of the Asynchronous Client Socket example code as a foundation for writing asynchronous communication procedures, may I ask if anyone can please suggest a replacement routine that is more reliable? There are three pieces of equipment, each with it's own ip-address and port number. Thus, it would be ideal if a class could be utilized, where an instance could be created for each device. Additionally, the port must remain open to receive spontaneous updates continually sent by the equipment. Lastly, the updates do not have a end character or defined length signalling that the transmission of the message is complete, thus the routine must continually poll the port for available data. Any advice or suggestions would be greatly appreciated.
7/18/2012 - WORKAROUND: After spending a considerable amount of time attempting to get the MSDN's Asynchronous Client Socket code sample working, it became clear that I would have to look elsewhere to get the device responses continuously recognized by the program. In the hope to save someone else the brain-damage, I have included the work-around that I used which seems to work well to this point. If anyone has any suggestions, please don't hesitate to add to this question!
//
// ORIGINAL CODE ATTEMPT
//
public static Socket LutronClient;
public static String LutronResponse = String.Empty;
private const int LutronPort = 4999;
private const string LutronIP = "192.168.1.71";
private static ManualResetEvent LutronConnectDone = new ManualResetEvent(false);
private static ManualResetEvent LutronSendDone = new ManualResetEvent(false);
private static ManualResetEvent LutronReceiveDone = new ManualResetEvent(false);
private static void StartLutronClient()
{
try
{
var lutronIPAddress = IPAddress.Parse(LutronIP);
var lutronRemoteEP = new IPEndPoint(lutronIPAddress, LutronPort);
LutronClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
LutronClient.BeginConnect(lutronRemoteEP, LutronConnectCallback, LutronClient);
LutronConnectDone.WaitOne();
LutronSend(LutronClient, "sdl,14,100,0,S2\x0d");
LutronSendDone.WaitOne();
LutronReceive(LutronClient);
LutronReceiveDone.WaitOne(new TimeSpan(5000));
MessageBox.Show("Response received from Lutron: " + LutronResponse);
txtBoxLutron.Text = LutronResponse;
LutronClient.Shutdown(SocketShutdown.Both);
LutronClient.Close();
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
}
private static void LutronConnectCallback(IAsyncResult lutronAr)
{
try
{
var lutronClient = (Socket)lutronAr.AsyncState;
lutronClient.EndConnect(lutronAr);
LutronConnectDone.Set();
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
}
private static void LutronReceive(Socket lutronClient)
{
try
{
var lutronState = new LutronStateObject { LutronWorkSocket = lutronClient };
lutronClient.BeginReceive(lutronState.LutronBuffer, 0, LutronStateObject.BufferSize, 0, new AsyncCallback(LutronReceiveCallback), lutronState);
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
}
private static void LutronReceiveCallback(IAsyncResult lutronAR)
{
try
{
var lutronState = (LutronStateObject)lutronAR.AsyncState;
var lutronClient = lutronState.LutronWorkSocket;
var bytesRead = lutronClient.EndReceive(lutronAR);
if (bytesRead > 0)
{
lutronState.LutronStringBuilder.AppendLine(Encoding.ASCII.GetString(lutronState.LutronBuffer, 0, bytesRead));
lutronClient.BeginReceive(lutronState.LutronBuffer, 0, LutronStateObject.BufferSize, 0, new AsyncCallback(LutronReceiveCallback), lutronState);
}
else
{
if (lutronState.LutronStringBuilder.Length > 0) { LutronResponse = lutronState.LutronStringBuilder.ToString(); }
LutronReceiveDone.Set();
}
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
}
public static void LutronSend(Socket client, String data)
{
var byteData = Encoding.ASCII.GetBytes(data);
client.BeginSend(byteData, 0, byteData.Length, 0, LutronSendCallback, client);
}
private static void LutronSendCallback(IAsyncResult ar)
{
try
{
var client = (Socket)ar.AsyncState;
var bytesSent = client.EndSend(ar);
LutronSendDone.Set();
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
}
public class LutronStateObject
{
public Socket LutronWorkSocket;
public const int BufferSize = 256;
public byte[] LutronBuffer = new byte[BufferSize];
public StringBuilder LutronStringBuilder = new StringBuilder();
}
}
This is the work-around I used:
//
// WORK-AROUND
//
using System;
using System.Windows.Forms;
namespace _GlobalCacheInterface
{
public partial class GlobalCacheDataScreen : Form
{
//Interface objects
private static GC_Interface _lutronInterface;
private const int LutronPort = 4999;
private const string LutronIP = "192.168.1.71";
delegate void ThreadSafeLutronCallback(string text);
private static GC_Interface _elanInterface;
private const int ElanPort = 4998;
private const string ElanIP = "192.168.1.70";
delegate void ThreadSafeElanCallback(string text);
private static GC_Interface _tuneSuiteInterface;
private const int TuneSuitePort = 5000;
private const string TuneSuiteIP = "192.168.1.70";
delegate void ThreadSafeTuneSuiteCallback(string text);
public GlobalCacheDataScreen()
{
InitializeComponent();
_lutronInterface = new GC_Interface(LutronIP, LutronPort);
_elanInterface = new GC_Interface(ElanIP, ElanPort);
_tuneSuiteInterface = new GC_Interface(TuneSuiteIP, TuneSuitePort);
// Create event handlers to notify application of available updated information.
_lutronInterface.DataAvailable += (s, e) => ThreadSafeTxtBoxLutron(_lutronInterface._returnString);
_elanInterface.DataAvailable += (s, e) => ThreadSafeTxtBoxElan(_elanInterface._returnString);
_tuneSuiteInterface.DataAvailable += (s, e) => ThreadSafeTxtBoxTuneSuite(_tuneSuiteInterface._returnString);
_lutronInterface.Connected += (s, e) => UpdateUI();
_elanInterface.Connected += (s, e) => UpdateUI();
_tuneSuiteInterface.Connected += (s, e) => UpdateUI();
UpdateUI();
}
private void UpdateUI()
{
_buttonConnectToLutron.Enabled = !_lutronInterface._isConnected;
_buttonConnectToElan.Enabled = !_elanInterface._isConnected;
_buttonConnectToTuneSuite.Enabled = !_tuneSuiteInterface._isConnected;
_buttonDisconnectFromLutron.Enabled = _lutronInterface._isConnected;
_buttonDisconnectFromElan.Enabled = _elanInterface._isConnected;
_buttonDisconnectFromTuneSuite.Enabled = _tuneSuiteInterface._isConnected;
string connectLutronStatus = _lutronInterface._isConnected ? "Connected" : "Not Connected";
string connectElanStatus = _elanInterface._isConnected ? "Connected" : "Not Connected";
string connectTuneSuiteStatus = _tuneSuiteInterface._isConnected ? "Connected" : "Not Connected";
_textBoxLutronConnectStatus.Text = connectLutronStatus;
_textBoxElanConnectStatus.Text = connectElanStatus;
_textBoxTuneSuiteConnectStatus.Text = connectTuneSuiteStatus;
}
private void ThreadSafeTxtBoxLutron(string message) { if (_lutronRichTextRxMessage.InvokeRequired) { var d = new ThreadSafeLutronCallback(ThreadSafeTxtBoxLutron); _lutronRichTextRxMessage.Invoke(d, new object[] { message }); } else { _lutronRichTextRxMessage.Text = message; } }
private void ThreadSafeTxtBoxElan(string message) { if (_elanRichTextRxMessage.InvokeRequired) { var d = new ThreadSafeElanCallback(ThreadSafeTxtBoxElan); _elanRichTextRxMessage.Invoke(d, new object[] { message }); } else { _elanRichTextRxMessage.Text = message; if (message.EndsWith("\r")) { MessageBoxEx.Show(message, "Message from Lutron Elan", 1000); } } }
private void ThreadSafeTxtBoxTuneSuite(string message) { if (_tuneSuiteRichTextRxMessage.InvokeRequired) { var d = new ThreadSafeTuneSuiteCallback(ThreadSafeTxtBoxTuneSuite); _tuneSuiteRichTextRxMessage.Invoke(d, new object[] { message }); } else { _tuneSuiteRichTextRxMessage.Text = message; if (message.EndsWith("\r")) { MessageBoxEx.Show(message, "Message from TuneSuite", 1000); } } }
private void _buttonConnectToLutron_Click(object sender, EventArgs e) { _lutronInterface.Connect(); }
private void _buttonDisconnectFromLutron_Click(object sender, EventArgs e) { _lutronInterface.Disconnect(); }
private void _buttonConnectToElan_Click(object sender, EventArgs e) { _elanInterface.Connect(); }
private void _buttonDisconnectFromElan_Click(object sender, EventArgs e) { _elanInterface.Disconnect(); }
private void _buttonConnectToTuneSuite_Click(object sender, EventArgs e) { _tuneSuiteInterface.Connect(); }
private void _buttonDisconnectFromTuneSuite_Click(object sender, EventArgs e) { _tuneSuiteInterface.Disconnect(); }
private void _buttonLutronSendMessage_Click(object sender, EventArgs e) { _lutronInterface.SendCommand(_lutronRichTextTxMessage.Text); }
private void _buttonElanSendMessage_Click(object sender, EventArgs e) { _elanInterface.SendCommand(_elanRichTextTxMessage.Text); }
private void _buttonTuneSuiteSendMessage_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand(_elanRichTextTxMessage.Text); }
private void _buttonLightOn_Click(object sender, EventArgs e) { _lutronInterface.SendCommand("sdl,14,100,0,S2"); }
private void _buttonLightOff_Click(object sender, EventArgs e) { _lutronInterface.SendCommand("sdl,14,0,0,S2"); }
private void _buttonStereoOnOff_Click(object sender, EventArgs e) { _elanInterface.SendCommand("sendir,4:3,1,40000,4,1,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,800"); }
private void _button30_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand("\xB8\x4D\xB5\x33\x30\x00\x30\x21\xB8"); }
private void _button31_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand("\xB8\x4D\xB5\x33\x31\x00\x30\x21\xB8"); }
private void _button26_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand("\xB8\x4D\xB5\x32\x36\x00\x30\x21\xB8"); }
}
}
and the GC_Interface class:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
namespace _GlobalCacheInterface
{
class GC_Interface
{
// Declare an event handler to notify when updates are available.
public event EventHandler<EventArgs> DataAvailable;
public string _returnString = "";
// Declare an event handler to notify status of connection.
public event EventHandler<EventArgs> Connected;
public bool _isConnected;
public AsyncCallback ReceiveCallback;
public Socket Client;
private string _ipAddress;
private int _port;
private bool _waitForEndCharacter;
private byte _endCharacter;
byte[] m_DataBuffer = new byte[10];
IAsyncResult m_Result;
public GC_Interface(string ipAddress, int port) { Init(ipAddress, port, false, 0); }
private void Init(string ipAddress, int port, bool waitForEndCharacter, byte endCharacter)
{
_ipAddress = ipAddress;
_port = port;
_waitForEndCharacter = waitForEndCharacter;
_endCharacter = endCharacter;
_isConnected = false;
}
public bool Connect()
{
try
{
// Create a TCP/IP socket.
Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Establish the remote endpoint for the socket.
var address = IPAddress.Parse(_ipAddress);
var remoteEP = new IPEndPoint(address, _port);
// Connect to the remote endpoint.
Client.Connect(remoteEP);
if (Client.Connected)
{
_isConnected = true;
ConnectedEventHandler();
WaitForData();
}
return true;
}
catch (SocketException se) { MessageBox.Show("\n connection failed, is the server running?\n" + se.Message ); return false; }
}
public bool SendCommand(string command)
{
try
{
// Convert the string data to byte data using ASCII encoding.
var byteData = Encoding.Default.GetBytes(command);
// Add a carraige-return to the end.
var newArray = new byte[byteData.Length + 1];
byteData.CopyTo(newArray, 0);
newArray[newArray.Length - 1] = 13;
if (Client == null) { return false; }
Client.Send(newArray);
return true;
}
catch (SocketException se) { MessageBox.Show(se.Message); return false; }
}
public void WaitForData()
{
try
{
if (ReceiveCallback == null) { ReceiveCallback = new AsyncCallback(OnDataReceived); }
var theSocPkt = new SocketPacket { thisSocket = Client };
m_Result = Client.BeginReceive(theSocPkt.DataBuffer, 0, theSocPkt.DataBuffer.Length, SocketFlags.None, ReceiveCallback, theSocPkt);
}
catch (SocketException se) { MessageBox.Show(se.Message); }
}
public class SocketPacket
{
public System.Net.Sockets.Socket thisSocket;
public byte[] DataBuffer = new byte[1];
}
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
var iRx = theSockId.thisSocket.EndReceive(asyn);
char[] Chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int CharLen = d.GetChars(theSockId.DataBuffer, 0, iRx, Chars, 0);
System.String szData = new System.String(Chars);
_returnString = _returnString + szData.Replace("\0", "");
// When an update is received, raise DataAvailable event
DataAvailableEventHandler();
WaitForData();
}
catch (ObjectDisposedException) { System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n"); }
catch (SocketException se) { MessageBox.Show(se.Message); }
}
public bool Disconnect()
{
try
{
if (Client == null) { return false; }
Client.Close();
Client = null;
_isConnected = false;
return true;
}
catch (Exception) { return false; }
}
protected virtual void DataAvailableEventHandler()
{
var handler = DataAvailable;
if (handler != null) { handler(this, EventArgs.Empty); }
}
protected virtual void ConnectedEventHandler()
{
var handler = Connected;
if (handler != null) { handler(this, EventArgs.Empty); }
}
}
}
I had the same issue, adding an Available check to the code fixed my problem. Below is the revised code.
private static void ReceiveCallback( IAsyncResult ar ) {
try {
StateObject state = (StateObject) ar.AsyncState;
Socket client = state.workSocket;
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0) {
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Check if there is anymore data on the socket
if (client.Available > 0) {
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
}
if (bytesRead == 0 || client.Available == 0) {
if (state.sb.Length > 1) {
response = state.sb.ToString();
}
receiveDone.Set();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
Hope that helps.
I'm sidestepping the question here. I try to answer what you need, not what you ask for:
Use synchronous code. It will be easier to understand, you don't need callbacks or events. Also, for low thread counts, it is likely to perform better.
You also avoid bugs that you have in your current code. If an exception occurs your computation never completes. Synchronous code does not have that problem.

Server and Java Applet: Connecting Socket

I have a java applet recently stopped working after the server is updated, more specifically:
1. The server is updated from Sun, running Solaris 9, 32 bit. (installed in 2005) to CentOS 5, (linux) on 64 bit.
2. The applet has two major classes 1) collect.class: collects data from a canvas 2) server.class: listens to collect.class through a PORT and acts accordingly;
but the applet got stuck and I check the start_server.sh (which produces a report nohup.out) there is a line
Exception creating server socket: java.net.BindException: Address already in use
This is weird, because PORT = 9999 which collect.class uses with no problem. How comes the problem happens only in server.class (who listens to collet.class).
Please help!
ADDITIONAL INFORMATION:
I.IN COLLECT.JAVA:
There is a canvas with grid on it, the user draw some area on the grid and click "Submit".
-> The MineCanvas.submit() is triggered -> The value of the area is computed by MineCanvas.ComputeGridValue() -> then Collect.cleintSend (stuck here)
import java.applet.*;
import java.awt.*;
import java.net.*;
import java.io.*;
import java.util.*;
public class Collect extends Applet {
...
public static final int PORT = 8888;
...
public boolean action(Event e, Object arg) {
...
if (arg.equals("Submit")) {
if (action(null, "Update Grid")) {
minecanvas.Submit();
} else {
return true;
}
}
return true;
}
...
public void clientSend(){
s = new Socket(this.getCodeBase().getHost(), PORT);
in = new DataInputStream(s.getInputStream());}
out = new DataOutputStream(s.getOutputStream());
listener = new SolutionListener(in, minecanvas);}
minecanvas.mode = MineCanvas.SUBMITTING;
minecanvas.repaint();
int n = 1;
out.writeBytes(minecanvas.gridh + "\n" + minecanvas.gridw + "\n");
for (int h = 0; h < minecanvas.gridh; h++) {
for (int w = 0; w < minecanvas.gridw; w++) {
out.writeBytes(n + " " + minecanvas.AllCells[w][h].net + "\n");
n++;
}
}
out.writeBytes("done\n");
s = null;
in = null;
out = null;
}
}
class MineCanvas extends Canvas {
...
public int gridw = 0; // number of grid squares width-ly
public int gridh = 0; // number of grid squares height-ly
public GridCell[][] AllCells; // array of grid cells comprising the grid
...
// compute values for minecanvas
public void ComputeGridValue() {...}
public void Submit() {
ComputeGridValue();
parent.clientSend();
}
...
}
...
}
II. SERVER.JAVA
import java.io.*;
import java.net.*;
public class Server extends Thread {
private OPM_Server opm; // this is the corresponding server for collect
...
public Server() {
...
opm = new OPM_Server();
}
public static void main(String[] args) {
new Server();
}
}
...
// OPM: correspond to Collect
class OPM_Server extends Thread {
public final static int DEFAULT_PORT = 8888;
protected int port;
protected ServerSocket listen_socket;
public static void fail(Exception e, String msg) {
System.err.println(msg + ": " + e);
System.exit(1);
}
public OPM_Server() {
this.port = DEFAULT_PORT;
try { listen_socket = new ServerSocket(port); }
catch (IOException e){ fail(e, "Exception creating server socket");}
System.out.println("Server: listening on port " + port);
this.start();
}
public void run() {
try {
while(true) {
System.out.println("I got to before ServerSocket");
Socket client_socket = listen_socket.accept();
OPM_Connection c = new OPM_Connection(client_socket);
}
}
catch (IOException e) {fail(e, "Exception while listening for connections");}
}
}
...
class OPM_Connection extends Thread {
protected Socket client;
protected BufferedReader in;
protected DataOutputStream out;
File mine_data = new File("mine_data"); // output file data
FileOutputStream file_stream;
DataOutputStream file_out;
public OPM_Connection(Socket client_socket) {
client = client_socket;
try {
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
try {
client.close();
} catch (IOException e2) {
}
;
System.err.println("Exception while getting socket stream: "
+ e.toString());
return;
}
this.start();
}
public void run() {
...
file_stream = new FileOutputStream(mine_data);
file_out = new DataOutputStream(file_stream);
...// write to mine data
file_out = null;
if (inputGood == true) {
System.out.println(pid + "> ---Got all info from client");
Runtime r = Runtime.getRuntime();
Process Aproc = null;
Process Bproc = null;
int returnVal = -1;
try {
Aproc = r.exec("runOPM");
} catch (IOException e) {
inputGood = false;
System.out.println(pid + "> runOPM didn't exec");
}
try {
returnVal = Aproc.waitFor();
} catch (InterruptedException e) {
inputGood = false;
System.out.println(pid + "> runOPM didn't return");
}
System.out.println(pid + "> ---All execing done");
File report = new File("mine_report");
FileInputStream report_stream = null;
...
// create a mine report
System.out.println(pid + "> ---Done sending data back to client");
}
try {
client.close();
} catch (IOException e2) {
}
;
System.out.println(pid + "> EXITING THREAD");
}
}
Exception creating server socket: java.net.BindException: Address
already in use
This exception means that the port number the socket is trying to bind to (the port number your socket is trying to use in the local-end of the connection) is already in use by some other program. To fix it, you either need to find out what other software is using the port and see if you can safely change it, or change the port your program is using.
Edit: It might be worth trying to look for rarely used port(s), to lessen the chance of using yet another port that is known to be used by some common software, here's Wikipedias list of typical TCP and UDP ports in use by common programs and services.