Sending a Protocol Buffer Message from a Java Client to C++ Server - protocol-buffers

Im trying to send a Protocol buffer message from a Java Client to a C++ Server. After runing the server and the client i just get "0" as a value for the Api field, even i set it as "1" in the Java client side.
The Java Client code looks like this:
public static void main(String[] args) throws IOException {
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
//the protocol buffers message is called INFO and have only one field Api
INFO info = INFO.newBuilder()
.setApi(1)
.build();
try {
echoSocket = new Socket("localhost", 30000);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: Localhost.");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for "
+ "the connection to: Localhost.");
System.exit(1);
}
out.println((info.toByteArray())); // serialize and the message
System.out.println("send ");
}
}
And the C++ server code looks like this:
int main ( int argc, int argv[] ){
INFO info;
try
{
// Create the socket
ServerSocket server ( 30000 );
while ( true )
{
ServerSocket new_sock;
server.accept ( new_sock );
try
{
while(true){
std::string data;
// in the next i'll i receive Data from the Java client i already test it with a string, and it works
new_sock >> data;
info.ParseFromString(data);
cout << "api: " << info.api() << endl;
}
}
catch ( SocketException& ) {}
}
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
}
return 0;
}
I am not sure what I am doing wrong. I don't know if I am serializing an parsing correctly. i didn't get any errors only a false Api value. Please let me know if you see any problems! Thanks a lot!

I think the problem is with:
new_sock >> data;
Verify that the number of bytes read in for data is the same as the size of info.toByteArray(). My guess is they're different, in which case you need to change the way that you're read(2)ing data from new_sock (newline delimited IO by default?).

Related

Incorrect file being produced using websockets in helidon

I am trying to upload a file using websockets in Helidon.I think i am doing it write the right way but the code seems to be flaky in terms of the size of the file produced which is different. The size of the file being produced is different for different runs.
How can i make sure that the file size is same on both ends?
I use a simple protocol for handshake[code below]:
Step1 client sends filesize=11000 buffer=5000
Step2 server sends SENDFILE
Step3 client >> buffer 1 server >> write 1 5000
Step4 client >> buffer 2 server >> write 2 5000
Step5 client >> buffer 3 server >> write 3 1000
Step6 client sends ENDOFFILE server >> session.close
//SERVER side OnOpen session below
session.addMessageHandler(new MessageHandler.Whole<String>() {
#Override
public void onMessage(String message) {
System.out.println("Server >> " + message);
if (message.contains("FILESIZE")) {
session.getBasicRemote().sendText("SENDFILENOW");
}
if(message.contains("ENDOFFILE")) {
System.out.println("Server >> FILE_SIZE=" + FILE_SIZE);
finalFileOutputStream.close();
session.close();
}
}
});
session.addMessageHandler(new MessageHandler.Whole<ByteBuffer>() {
#Override
public void onMessage(ByteBuffer b) {
finalFileOutputStream.write(b.array(), 0, b.array().length);
finalFileOutputStream.flush();
}
});
//CLIENT OnOpen session below
session.getBasicRemote().sendText("FILESIZE=" + FILE_SIZE);
session.addMessageHandler(new MessageHandler.Whole<String>() {
#Override
public void onMessage(String message) {
long M = FILE_SIZE / BUFFER_SIZE;
long R = FILE_SIZE % BUFFER_SIZE;
if(!message.equals("SENDFILENOW"))
return;
try {
System.out.println("Starting File read ... " + path + " " + FILE_SIZE + " " + M + " " +message );
byte[] buffer = new byte[(int) BUFFER_SIZE];
while (M > 0) {
fileInputStream.read(buffer);
ByteBuffer bytebuffer = ByteBuffer.wrap(buffer);
session.getBasicRemote().sendBinary(bytebuffer);
M--;
}
buffer = new byte[(int) R];
fileInputStream.read(buffer, 0, (int) R);
fileInputStream.close();
ByteBuffer bytebuffer = ByteBuffer.wrap(buffer);
session.getBasicRemote().sendBinary(bytebuffer);
session.getBasicRemote().sendText("FILEREADDONE");
session.close();
f.complete(true);
} catch (IOException e) {
fail("Unexpected exception " + e);
}
}
});
Your solution is unnecessarily built on top of several levels of abstraction just to use websockets. Do you really need that? Helidon is very well equipped to handle huge file upload directly and much more efficiently.
public class LargeUpload {
public static void main(String[] args) {
ExecutorService executor = ThreadPoolSupplier.create("upload-thread-pool").get();
WebServer server = WebServer.builder(Routing.builder()
.post("/streamUpload", (req, res) -> req.content()
.map(DataChunk::data)
.flatMapIterable(Arrays::asList)
.to(IoMulti.writeToFile(createFile(req.queryParams().first("fileName").orElse("bigFile.mkv")))
.executor(executor)
.build())
.onError(res::send)
.onComplete(() -> {
res.status(Http.Status.ACCEPTED_202);
res.send();
}).ignoreElement())
.build())
.port(8080)
.build()
.start()
.await(Duration.ofSeconds(10));
// Server started - do upload
//several gigs file
Path file = Path.of("/home/kec/helidon-kafka.mkv");
try (FileInputStream fis = new FileInputStream(file.toFile())) {
WebClient.builder()
.baseUri("http://localhost:8080")
.build()
.post()
.path("/streamUpload")
.queryParam("fileName", "bigFile_" + System.currentTimeMillis() + ".mkv")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.submit(IoMulti.multiFromByteChannelBuilder(fis.getChannel())
.bufferCapacity(1024 * 1024 * 4)
.build()
.map(DataChunk::create)
)
.await(Duration.ofMinutes(10));
} catch (IOException e) {
throw new RuntimeException(e);
}
executor.shutdown();
server.shutdown()
.await(Duration.ofSeconds(10));
}
static Path createFile(String path) {
try {
Path filePath = Path.of("/home/kec/tmp/" + path);
System.out.println("Creating " + filePath);
return Files.createFile(filePath);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

JPOS testing (Functional and Perf ) using Apache Jmeter

I want to perform functional test of JPOS based ISO message and response(TPS) using Jmeter.Can anyone guide me on this?Do I need to install any plugin in Jmeter.As I have tried to install the Jmeter in my system.But Can't see any Jpos plugin in listeners to start with.Dev is Using Socket connection in Jpos.
I don't think you will be able to find any plugin, however you should be able to use jPOS client library from the JSR223 Sampler
Download the jPOS and build it using Gradle
Copy jpos/build/libs/jpos-x.x.x.jar to JMeter Classpath (along with dependencies, if you don't have them yet)
Restart JMeter to pick the library up
Add JSR223 Sampler to your Test Plan and put the code, implementing your test scenario into "Script" area, an example would be something like:
import org.jpos.iso.ISOMsg
import org.jpos.iso.channel.ASCIIChannel
import org.jpos.iso.packager.ISO87APackager
def host = 'your_host'
def port = 1234
def channel = new ASCIIChannel(host, port, new ISO87APackager())
channel.connect()
def message = new ISOMsg()
message.setMTI("0800")
message.set(3, "000000")
message.set(41, "00000001")
message.set(70, "301")
channel.send(message)
ISOMsg response = channel.receive()
channel.disconnect()
More information:
jPOS Programmer’s Guide
Apache Groovy - Why and How You Should Use It
We can send a XML or rawMessage to jpos server from the Jmeter TCPSampler
You can also add TPS listeners
enter image description here
And JPosTCPClient can be implemented
public class JPosTCPClient extends TCPClientImpl {
private static final Logger log = LoggingManager.getLoggerForClass();
private String containsString = "</isomsg>";
private boolean filterEnabled = true;
public JPosTCPClient() {
filterEnabled = Boolean.parseBoolean(JMeterUtils.getPropDefault("jpos.tcp.use", "true"));
containsString = JMeterUtils.getPropDefault("jpos.tcp.contains", "</isomsg>");
}
/**
* Reads data until the defined EOL byte is reached.
* If there is no EOL byte defined, then reads until
* the end of the stream is reached.
*/
#Override
public String read(InputStream is) {
byte[] buffer = new byte[4096];
ByteArrayOutputStream w = new ByteArrayOutputStream();
int x = 0;
boolean contains = false;
try {
while ((x = is.read(buffer)) > -1) {
w.write(buffer, 0, x);
if(filterEnabled){
String response = new String(buffer);
if(response.contains(containsString)){
contains = true;
break;
} else {
System.out.println("Contents: " + response);
}
}
}
if(filterEnabled && !contains){
System.out.println("Skipped containsString checking, x length:" + x);
}
} catch (SocketTimeoutException e) {
// drop out to handle buffer
System.out.println(e.getMessage());
} catch (InterruptedIOException e) {
// drop out to handle buffer
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
log.warn("Read error:" + e);
return "";
}
// do we need to close byte array (or flush it?)
log.debug("Read: " + w.size() + "\n" + w.toString());
return w.toString();
}
}

SSE server sending events in a batch on final close

I have a Jersey server running locally, it exposes a SSE resource just like the examples here: https://jersey.github.io/documentation/latest/sse.html. I have a local webpack Angular app, that binds to the exposed GET endpoint and listens for data.
On the GET, I start up a thread to send notifications at regular intervals over 6-8 seconds. I don't see anything on the client UNTIL the EventOutput object is closed.
What am I doing wrong, and how can I fix this?
The server code WORKS with just a simple curl, i.e.:
curl http://localhost:8002/api/v1/notify
But on both Chrome and Safari the following code exhibits the behavior
Client (TypeScript):
this.evSource = new EventSource('http://localhost:8002/api/v1/notify');
this.evSource.addEventListener(
'event',
(x => console.log('we have ', x))
);
this.evSource.onmessage = (data => console.log(data));
this.evSource.onopen = (data => console.log(data));
this.evSource.onerror = (data => {
console.log(data);
this.evSource.close();
});
Server (Java):
// cache callback
public void eventCallback(Iterable<CacheEntryEvent<? extends Integer, ? extends Integer>> events) {
for (CacheEntryEvent<? extends Integer, ? extends Integer> x : events) {
LOGGER.info("{} Sending the following value: " + x.getValue(), Thread.currentThread().getId());
final OutboundEvent sseEvent = new OutboundEvent.Builder().name("event")
.data(Integer.class, x.getValue()).build();
this.broadcaster.broadcast(sseEvent);
}
}
#GET
#Produces(SseFeature.SERVER_SENT_EVENTS)
#ApiOperation(value = "Setup SSE pipeline", notes = "Sets up the notification pipeline for clients to access")
#ApiResponses(value = {
#ApiResponse(code = HttpURLConnection.HTTP_UNAUTHORIZED,
message = "Missing, bad or untrusted cookie"),
#ApiResponse(code = HttpURLConnection.HTTP_OK,
message = "Events streamed successfully")
})
#Timed
#ResponseMetered
public EventOutput registerNotificationEvents(
#HeaderParam(SseFeature.LAST_EVENT_ID_HEADER) String lastEventId,
#QueryParam(SseFeature.LAST_EVENT_ID_HEADER) String lastEventIdQuery) {
if (!Strings.isNullOrEmpty(lastEventId) || !Strings.isNullOrEmpty(lastEventIdQuery)) {
LOGGER.info("Found Last-Event-ID header: {}", !Strings.isNullOrEmpty(lastEventId) ? lastEventId : lastEventIdQuery );
}
LOGGER.info("{} Received request", Thread.currentThread().getId());
this.continuation = true;
final EventOutput output = new EventOutput();
broadcaster.add(output);
Random rand = new Random();
IntStream rndStream = IntStream.generate(() -> rand.nextInt(90));
List<Integer> lottery = rndStream.limit(15).boxed().collect(Collectors.toList());
IgniteCache<Integer, Integer> cache = this.ignite.cache(topic_name);
executorService.execute(() -> {
try {
lottery.forEach(value -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
LOGGER.info("{} Sending the following value to Ignite: " + value + " : " + count++, Thread.currentThread().getId());
if (!cache.isClosed()) {
cache.put(1, value);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
TimeUnit.MILLISECONDS.sleep(500);
continuation = false;
TimeUnit.MILLISECONDS.sleep(500);
if (!output.isClosed()) {
// THIS is where the client sees ALL the data broadcast
// in one shot
output.close();
}
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
});
LOGGER.info("{} Completing request", Thread.currentThread().getId());
return output;
}
}
Looks like http://github.com/dropwizard/dropwizard/issues/1673 captures the problem. GZip default won't flush even if upper levels ask for it. Solution is something like
((AbstractServerFactory)configuration.getServerFactory()).getGzipFilterFactory().setSyncFlush(true);
will enable flushing to synchronize with GZip if disabling GZip all up is not an option

Windows phone a socket operation encountered a dead network

I am trying to get the IP address of networks like Wi-Fi,Data Network. I use the following class to find the IP.
public class MyIPAddress
{
Action<IPAddress> FoundCallback;
UdpAnySourceMulticastClient MulticastSocket;
const int PortNumber = 50000; // pick a number, any number
string MulticastMessage = "FIND-MY-IP-PLEASE" + new Random().Next().ToString();
public void Find(Action<IPAddress> callback)
{
FoundCallback = callback;
MulticastSocket = new UdpAnySourceMulticastClient(IPAddress.Parse("239.255.255.250"), PortNumber);
MulticastSocket.BeginJoinGroup((result) =>
{
try
{
MulticastSocket.EndJoinGroup(result);
GroupJoined(result);
}
catch (Exception ex)
{
// Debug.WriteLine("EndjoinGroup exception {0}", ex.Message);
// This can happen eg when wifi is off
FoundCallback(null);
}
},
null);
}
void callback_send(IAsyncResult result)
{
}
byte[] MulticastData;
bool keepsearching;
void GroupJoined(IAsyncResult result)
{
MulticastData = Encoding.UTF8.GetBytes(MulticastMessage);
keepsearching = true;
MulticastSocket.BeginSendToGroup(MulticastData, 0, MulticastData.Length, callback_send, null);
while (keepsearching)
{
try
{
byte[] buffer = new byte[MulticastData.Length];
MulticastSocket.BeginReceiveFromGroup(buffer, 0, buffer.Length, DoneReceiveFromGroup, buffer);
}
catch (Exception ex)
{
// Debug.WriteLine("Stopped Group read due to " + ex.Message);
keepsearching = false;
}
}
}
void DoneReceiveFromGroup(IAsyncResult result)
{
string str = "";
IPEndPoint where;
int responselength = MulticastSocket.EndReceiveFromGroup(result, out where);
byte[] buffer = result.AsyncState as byte[];
if (responselength == MulticastData.Length && buffer.SequenceEqual(MulticastData))
{
str = where.Address.ToString();
keepsearching = false;
FoundCallback(where.Address);
}
Console.WriteLine(str);
}
}
I was successful to find out the IP address of connected Wi-Fi. I turn off Wi-Fi and turn on the Data Connection. I am not able to get the IP address of connected network. I got the error ** a socket operation encountered a dead network**. I have also refer this question A socket operation encountered a dead network. How can I solve this problem ?
Question is a bit old, but answer may be useful for someone:
You get this error, because your MyIPAddress class can only find a local IP (the address inside your internal WiFi network, behind router). To get an external IP address you should call an external server that will tell you your IP (eg. whatismyip.com).

BlackBerry - Downloaded images are corrupted on wifi with HttpConnection

In my app I need to download several images from a server. I use this code to get a byte array :
HttpConnection connection = null;
InputStream inputStream = null;
byte[] data = null;
try
{
//connection = (HttpConnection)Connector.open(url);
connection = (HttpConnection)Connector.open(url, Connector.READ_WRITE, true);
int responseCode = connection.getResponseCode();
if(responseCode == HttpConnection.HTTP_OK)
{
inputStream = connection.openInputStream();
data = IOUtilities.streamToBytes(inputStream);
inputStream.close();
}
connection.close();
return data;
}
catch(IOException e)
{
return null;
}
The url are formed with the suffix ";deviceSide=false;ConnectionType=MDS - public" (without spaces) and it is working perfectly well.
The problem is that with phones that do not have a sim card, we can't connect to the internet via the MDS server. So we changed to use the connection factory and let BB choose whatever he wants :
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection(url);
if (connDesc != null)
{
final HttpConnection httpConn;
httpConn = (HttpConnection)connDesc.getConnection();
try
{
httpConn.setRequestMethod(HttpConnection.GET);
final int iResponseCode = httpConn.getResponseCode();
if(iResponseCode == HttpConnection.HTTP_OK)
{
InputStream inputStream = null;
try{
inputStream = httpConn.openInputStream();
byte[] data = IOUtilities.streamToBytes(inputStream);
return data;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
finally{
try
{
inputStream.close();
} catch (IOException e)
{
e.printStackTrace();
return null;
}
}
}
}
catch (IOException e)
{
System.err.println("Caught IOException: " + e.getMessage());
}
}
return null;
The connection works because it select the good prefix (interface=wifi in our case), but this create another problem.
Some images are not well downloaded, some of them (not the sames at each try) are corrupted, but only when the phone use a wifi connection to get these images.
How can I avoid this problem ? What method to get a connection do I have to use ? Is it possible to check if the user have a sim card in orderto use MDS - public ?
Here is an example of a corrupted image :
error image http://nsa30.casimages.com/img/2012/06/28/120628033716123822.png
try this:
public static String buildURL(String url) {
String connParams = "";
if (WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED) {
connParams = ";interface=wifi"; //Connected to a WiFi access point.
} else {
int coverageStatus = CoverageInfo.getCoverageStatus();
//
if ((coverageStatus & CoverageInfo.COVERAGE_BIS_B) == CoverageInfo.COVERAGE_BIS_B) {
connParams = ";deviceside=false;ConnectionType=mds-public";
} else if ((coverageStatus & CoverageInfo.COVERAGE_DIRECT) == CoverageInfo.COVERAGE_DIRECT) {
// Have network coverage and a WAP 2.0 service book record
ServiceRecord record = getWAP2ServiceRecord();
//
if (record != null) {
connParams = ";deviceside=true;ConnectionUID=" + record.getUid();
} else {
connParams = ";deviceside=true";
}
} else if ((coverageStatus & CoverageInfo.COVERAGE_MDS) == CoverageInfo.COVERAGE_MDS) {
// Have an MDS service book and network coverage
connParams = ";deviceside=false";
}
}
Log.d("connection param"+url+connParams);
//
return url+connParams;
}
private static ServiceRecord getWAP2ServiceRecord() {
String cid;
String uid;
ServiceBook sb = ServiceBook.getSB();
ServiceRecord[] records = sb.getRecords();
//
for (int i = records.length -1; i >= 0; i--) {
cid = records[i].getCid().toLowerCase();
uid = records[i].getUid().toLowerCase();
//
if (cid.indexOf("wptcp") != -1
&& records[i].getUid().toLowerCase().indexOf("wap2") !=-1
&& uid.indexOf("wifi") == -1
&& uid.indexOf("mms") == -1) {
return records[i];
}
}
//
return null;
}
What happens when you append interface=wifi? Can you run the network diagnostic tool attached to below kb article and run all tests with SIM removed
http://supportforums.blackberry.com/t5/Java-Development/What-Is-Network-API-alternative-for-legacy-OS/ta-p/614822
Please also note that when download large files over BES/MDS there are limits imposed by MDS. Please ensure you review the below kb article
http://supportforums.blackberry.com/t5/Java-Development/Download-large-files-using-the-BlackBerry-Mobile-Data-System/ta-p/44585
You can check to see if coverage is sufficient for BIS_B (MDS public) but that won't help you if you are trying to support SIM-less users. I wonder if the problem is in an incomparability between the connection on Wi-Fi and IOUtilities.streamToBytes(). Try coding as recommended in the API documents.

Resources