I have the websocket examples for Mongoose 6.12 running well on my embedded platform.
What I am wondering is how is it possible to manage multiple URL of websockets?
Our goal is to have multiple web pages on our platform, each one periodically retrieving data over websockets from the server. Depending on the websocket URL, different set of data would be returned.
Using the example "websocket_chat" as a reference, the sending of code :
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
if (c == nc) continue;
mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, buf, strlen(buf));
}
would ideally filter out the URL that are not related to the URL being serviced:
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
if ((c == nc) **|| (strcmp(c->uri, "/ws/page1") == 0)**) continue;
mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, buf, strlen(buf));
}
But it seems that the connection doesn't hold the URL associated to the connection.
This code is called periodically by the web server, not based on an Mongoose event.
Do you have any suggestions on how to achieve this?
Many thanks.
Fred.
I think you can catch MG_EV_WEBSOCKET_HANDSHAKE_REQUEST event, which has access to the URI, and which can set the marker in the user_data:
static void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
switch (ev) {
case MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: {
struct http_message *hm = (struct http_message *) ev_data;
c->user_data = "foo";
if (mg_vcmp(&hm->uri, "/uri1") == 0) c->user_data = "bar";
break;
}
Then in the broadcast handler, check the value of that marker.
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
if (c == nc) continue; /* Don't send to the sender. */
if (c->user_data && strcmp(c->user_data, "bar") == 0)
mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, buf, strlen(buf));
}
}
Related
I know that this topic has been asked by many times and I search for all possible solutions but unfortunately nothing solves my problem.
Here's my test case:
#Test
public void whenFindAllBy_thenReturnListofViewPlanDetailDto() {
java.sql.Date startDate = new java.sql.Date(new Date().getTime());
java.sql.Date endDate = new java.sql.Date(new Date().getTime());
Plan planA = new Plan();
planA.setName("Plan A - 2018");
entityManager.persist(planA);
entityManager.flush();
Module moduleA = new Module();
moduleA.setName("CSS");
moduleA.setDescription("CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript.");
entityManager.persist(moduleA);
Module moduleB = new Module();
moduleB.setName("HTML");
moduleB.setDescription("Hypertext Markup Language is the standard markup language for creating web pages and web applications.");
entityManager.persist(moduleB);
PlanDetail planDetailA = new PlanDetail();
planDetailA.setInstructor("Mozilla Firefox Foundation");
planDetailA.setStartDate(startDate);
planDetailA.setEndDate(endDate);
planDetailA.setModule(moduleA);
planDetailA.setPlan(planA);
entityManager.persist(planDetailA);
PlanDetail planDetailB = new PlanDetail();
planDetailB.setInstructor("W3 Schools");
planDetailB.setStartDate(startDate);
planDetailB.setEndDate(endDate);
planDetailB.setModule(moduleB);
planDetailB.setPlan(planA);
entityManager.persist(planDetailB);
entityManager.flush();
List<ViewPlanDetailDto> plandetails = new ArrayList<>();
plandetails.add(new ViewPlanDetailDto(planDetailA.getId(), planDetailA.getModule().getName(), planDetailA.getModule().getDescription(), planDetailA.getInstructor(), planDetailA.getStartDate(), planDetailA.getEndDate()));
plandetails.add(new ViewPlanDetailDto(planDetailB.getId(), planDetailB.getModule().getName(), planDetailB.getModule().getDescription(), planDetailB.getInstructor(), planDetailB.getStartDate(), planDetailB.getEndDate()));
assertEquals(planRepository.findAllBy(planA.getId()), plandetails);
}
Stacktrace:
java.lang.AssertionError: expected: java.util.ArrayList<[ViewPlanDetailDto(detailId=1, name=CSS, description=CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript., instructor=Mozilla Firefox Foundation, startDate=2018-07-06, endDate=2018-07-06), ViewPlanDetailDto(detailId=2, name=HTML, description=Hypertext Markup Language is the standard markup language for creating web pages and web applications., instructor=W3 Schools, startDate=2018-07-06, endDate=2018-07-06)]> but was: java.util.ArrayList<[ViewPlanDetailDto(detailId=1, name=CSS, description=CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript., instructor=Mozilla Firefox Foundation, startDate=2018-07-06, endDate=2018-07-06), ViewPlanDetailDto(detailId=2, name=HTML, description=Hypertext Markup Language is the standard markup language for creating web pages and web applications., instructor=W3 Schools, startDate=2018-07-06, endDate=2018-07-06)]>
What I try:
Override equals on PlanDetail, ViewPlanDetailDto, Plan
but it all failed.
Equals and Hashcode overrides:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof ViewPlanDetailDto))
return false;
ViewPlanDetailDto other = (ViewPlanDetailDto) obj;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (detailId == null) {
if (other.detailId != null)
return false;
} else if (!detailId.equals(other.detailId))
return false;
if (endDate == null) {
if (other.endDate != null)
return false;
} else if (!endDate.equals(other.endDate))
return false;
if (instructor == null) {
if (other.instructor != null)
return false;
} else if (!instructor.equals(other.instructor))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (startDate == null) {
if (other.startDate != null)
return false;
} else if (!startDate.equals(other.startDate))
return false;
return true;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((detailId == null) ? 0 : detailId.hashCode());
result = prime * result + ((endDate == null) ? 0 : endDate.hashCode());
result = prime * result + ((instructor == null) ? 0 : instructor.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((startDate == null) ? 0 : startDate.hashCode());
return result;
}
When I try to assert it it always fails even though the output is identical.
Based on IntelliJ's comparison failure, it highlighted on the trailing space on the expected part which I don't get how it ended having a trailing space.
You probably override equals() incorrectly .
To understand and correct your issue, you should start by the base : unit testing your equals() method (and by the way think of overriding hashCode() to be consistent with the equals() contract).
Whatever, overriding equals() by specifying all instance fields of the class to do some assertions in an unit test is generally something that you can avoid and that you have to if it gives an undesirable behavior to equals().
equals() has a semantic defined in Object.equals() :
Indicates whether some other object is "equal to" this one.
You should stick to that.
Generally I use a unit testing matcher library such as Harmcrest or AssertJ to perform assertions on the object's field in a non intrusive while being simple and clear.
With AssertJ, your assertion could look like :
Assertions.assertThat(planRepository.findAllBy(planA.getId()))
// assert result size
.hasSize(2)
// extract a field to assert
.extracting(ViewPlanDetailDto::getPlanDetail)
// extract still finer fields to assert
.extracting(PlanDetail::getId, p -> p.getModule().getName(), p -> p.getModule().geDescription(), ... other fields to assert)
// declare values expected
.containsExactly(Tuple.tuple(planDetailA.getId(), "CSS", "CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript.",
planDetailB.getId(), "HTML", "Hypertext Markup Language is the standard markup language for creating web pages and web applications.",
... other expected tuples ));
I have a problem that I managed to fix... However I'm a little concerned as I don't really understand why the solution worked;
I am using NetMQ, and specifically a NetMQ poller which has a number of sockets, one of which is a REQ-REP pair.
I have a queue of requests which get dequeued into requests, and the server handles each request type as required and sends back an appropriate response. This had been working without issue, however when I tried to add in an additional request type the system stopped working as expected; what would occur is that the request would reach the server, the server would send the response... and the client would not receive it. The message would not be received at the client until the server was shut down (unusual behavior!).
I had been managing the REQ-REP pair with a flag that I set before sending a request, and reset on receipt of a reply. I managed to fix the issue by only triggering replies within the "SendReady" event of the REQ socket - this automagically fixed all of my issues, however I can't really find anything in the documentation that tells me why the socket might not have been in the "sendready" state, or what this actually does.
Any information that could be shed on why this is working now would be great :)
Cheers.
Edit: Source
Client:
"Subscribe" is run as a separate thread to the UI
private void Subscribe(string address)
{
using (var req = new RequestSocket(address + ":5555"))
using (var sub = new SubscriberSocket(address + ":5556"))
using (var poller = new NetMQPoller { req, sub })
{
// Send program code when a request for a code update is received
sub.ReceiveReady += (s, a) =>
{
var type = sub.ReceiveFrameString();
var reply = sub.ReceiveFrameString();
switch (type)
{
case "Type1":
manager.ChangeValue(reply);
break;
case "Type2":
string[] args = reply.Split(',');
eventAggregator.PublishOnUIThread(new MyEvent(args[0], (SimObjectActionEventType)Enum.Parse(typeof(MyEventType), args[1])));
break;
}
};
req.ReceiveReady += Req_ReceiveReady;
poller.RunAsync();
sub.Connect(address + ":5556");
sub.SubscribeToAnyTopic();
sub.Options.ReceiveHighWatermark = 10;
reqQueue = new Queue<string[]>();
reqQueue.Enqueue(new string[] { "InitialiseClient", "" });
req_sending = false;
while (programRunning)
{
if (reqQueue.Count > 0 && !req_sending)
{
req_sending = true;
string[] request = reqQueue.Dequeue();
Console.WriteLine("Sending " + request[0] + " " + request[1]);
req.SendMoreFrame(request[0]).SendFrame(request[1]);
}
Thread.Sleep(1);
}
}
}
private void Req_ReceiveReady(object sender, NetMQSocketEventArgs e)
{
var req = e.Socket;
var messageType = req.ReceiveFrameString();
Console.WriteLine("Received {0}", messageType);
switch (messageType)
{
case "Reply1":
// Receive action
break;
case "Reply2":
// Receive action
break;
case "Reply3":
// Receive action
break;
}
req_sending = false;
}
Server:
using (var rep = new ResponseSocket("#tcp://*:5555"))
using (var pub = new PublisherSocket("#tcp://*:5556"))
using (var beacon = new NetMQBeacon())
using (var poller = new NetMQPoller { rep, pub, beacon })
{
// Send program code when a request for a code update is received
rep.ReceiveReady += (s, a) =>
{
var messageType = rep.ReceiveFrameString();
var message = rep.ReceiveFrameString();
Console.WriteLine("Received {0} - Content: {1}", messageType, message);
switch (messageType)
{
case "InitialiseClient":
// Send
rep.SendMoreFrame("Reply1").SendFrame(repData);
break;
case "Req2":
// do something
rep.SendMoreFrame("Reply2").SendFrame("RequestOK");
break;
case "Req3":
args = message.Split(',');
if (args.Length == 2)
{
// Do Something
rep.SendMoreFrame("Reply3").SendFrame("RequestOK");
}
else
{
rep.SendMoreFrame("Ack").SendFrame("RequestError - incorrect argument format");
}
break;
case "Req4":
args = message.Split(',');
if (args.Length == 2)
{
requestData = //do something
rep.SendMoreFrame("Reply4").SendFrame(requestData);
}
else
{
rep.SendMoreFrame("Ack").SendFrame("RequestError - incorrect argument format");
}
break;
default:
rep.SendMoreFrame("Ack").SendFrame("Error");
break;
}
};
// setup discovery beacon with 1 second interval
beacon.Configure(5555);
beacon.Publish("server", TimeSpan.FromSeconds(1));
// start the poller
poller.RunAsync();
// run the simulation loop
while (serverRunning)
{
// todo - make this operate for efficiently
// push updated variable values to clients
foreach (string[] message in pubQueue)
{
pub.SendMoreFrame(message[0]).SendFrame(message[1]);
}
pubQueue.Clear();
Thread.Sleep(2);
}
poller.StopAsync();
}
You are using the Request socket from multiple threads, which is not supported. You are sending on the main thread and receiving on the poller thread.
Instead of using regular queue try to use NetMQQueue, you can add it to the poller and enqueue from the UI thread. Then the sending is happening on the poller thread as well as the receiving.
You can read the docs here:
http://netmq.readthedocs.io/en/latest/queue/
Only thing I can think of is that the REP socket is ready to send only after you actually received a message fully (all parts).
recently,I read the source code about Java concurrent Jar,the code in FutureTask class is very hard to understand,the awaitDone method like this:
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
else if (q == null)
q = new WaitNode();
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
LockSupport.park(this);
}
}
so,the question is ,I don't understand the usage of waiters, and how is the removeWaiter method worked.
any help would be appreciated.
According to the FutureTask javadocs, the waiters datastructure is a Treiber Stack, a lock-free data structure.
When one thread notices that the future is set or cancelled, it notifies any other waiting threads they can continue (un-parks them).
I tried to make an example of simple socket server.
Build and run successfully. However it doesn't work well.
Client couldn't connect to this server.
How to solve this problem? I need your help, thanks.
import Foundation
let BUFF_SIZE = 1024
func initStruct<S>() -> S {
let struct_pointer = UnsafePointer<S>.alloc(1)
let struct_memory = struct_pointer.memory
struct_pointer.destroy()
return struct_memory
}
func sockaddr_cast(p: ConstUnsafePointer<sockaddr_in>) -> UnsafePointer<sockaddr> {
return UnsafePointer<sockaddr>(p)
}
func socklen_t_cast(p: UnsafePointer<Int>) -> UnsafePointer<socklen_t> {
return UnsafePointer<socklen_t>(p)
}
var server_socket: Int32
var client_socket: Int32
var server_addr_size: Int
var client_addr_size: Int
var server_addr: sockaddr_in = initStruct()
var client_addr: sockaddr_in = initStruct()
var buff_rcv: Array<CChar> = []
var buff_snd: String
server_socket = socket(PF_INET, SOCK_STREAM, 0);
if server_socket == -1
{
println("[Fail] Create Server Socket")
exit(1)
}
else
{
println("[Success] Created Server Socket")
}
server_addr_size = sizeof(server_addr.dynamicType)
memset(&server_addr, 0, UInt(server_addr_size));
server_addr.sin_family = sa_family_t(AF_INET)
server_addr.sin_port = 4000
server_addr.sin_addr.s_addr = UInt32(0x00000000) // INADDR_ANY = (u_int32_t)0x00000000 ----- <netinet/in.h>
let bind_server = bind(server_socket, sockaddr_cast(&server_addr), socklen_t(server_addr_size))
if bind_server == -1
{
println("[Fail] Bind Port");
exit(1);
}
else
{
println("[Success] Binded Port");
}
if listen(server_socket, 5) == -1
{
println("[Fail] Listen");
exit(1);
}
else
{
println("[Success] Listening : \(server_addr.sin_port) Port ...");
}
var n = 0
while n < 1
{
client_addr_size = sizeof(client_addr.dynamicType)
client_socket = accept(server_socket, sockaddr_cast(&client_addr), socklen_t_cast(&client_addr_size))
if client_socket == -1
{
println("[Fail] Accept Client Connection");
exit(1);
}
else
{
println("[Success] Accepted Client : \(inet_ntoa(client_addr.sin_addr)) : \(client_addr.sin_port)");
}
read(client_socket, &buff_rcv, UInt(BUFF_SIZE))
println("[Success] Received : \(buff_rcv)")
buff_snd = "\(strlen(buff_rcv)) : \(buff_rcv)"
write(client_socket, &buff_snd, strlen(buff_snd) + 1)
close(client_socket)
}
The port number in the socket address must be in big-endian byte order:
server_addr.sin_port = UInt16(4000).bigEndian
So your program actually listens on port 40975 (hex 0xA00F) and not
on port 4000 (hex 0x0FA0).
Another problem is here:
var buff_rcv: Array<CChar> = []
// ...
read(client_socket, &buff_rcv, UInt(BUFF_SIZE))
Your buffer is an empty array, but recv() expects a buffer of size BUFF_SIZE.
The behaviour is undefined. To get a buffer of the required size, use
var buff_rcv = [CChar](count:BUFF_SIZE, repeatedValue:0)
// ...
read(client_socket, &buff_rcv, UInt(buff_rcv.count))
Remark: Here you cast the address of an Int to the address of an socklen_t
and pass that to the accept() function:
client_socket = accept(server_socket, sockaddr_cast(&client_addr), socklen_t_cast(&client_addr_size))
That is not safe. If Int and socklen_t have different sizes then the behaviour
will be undefined. You should declare server_addr_size and client_addr_size
as socklen_t and remove the socklen_t_cast() function:
client_socket = accept(server_socket, sockaddr_cast(&client_addr), &client_addr_size)
As Martin R commented before, the write command shouldn't be using the swift string as that. Something like this will work properly:
write(client_socket, buff_snd.cStringUsingEncoding(NSUTF8StringEncoding)!, countElements(buff_snd) + 1)
I have this condition
if(Model.Bids != null && Model.Bids.Items != null && Model.Bids.Items.Count > 0)
{
...
}
Problem is, I think this is ugly. I could write a function that encapsulates this but I wonder if there is something else that would help me write something like just the important bits below without having to do the null checks. If not then this would be a handy language extension.
if(Model.Bids.Items.Count > 0)
{
...
}
For c# this two options achieve sort of what you want but I wouldn't put this in my software quickly.
Also I doubt this gets more readable or better understandable. There is one other option but that requires you to refactor you Model class chain. If you implement a NullObject for the type in Bids and the type in Item you can do if(Model.Bids.Items.Count > 0) because all types will not be null but have an implementation that handles the Empty state (much like String.Empty)
helpers
/* take a func, wrap in a try/catch, invoke compare */
bool tc(Func<bool> comp )
{
try
{
return comp.Invoke();
}
catch (Exception)
{
return false;
}
}
/* helper for f */
T1 f1<T,T1>(T root, Func<T, T1> p1) where T:class
{
T1 res = default(T1);
if (root != null)
{
res = p1.Invoke(root);
}
return res;
}
/* take a chain of funcs and a comp if the last
in the chain is still not null call comp (expand if needed) */
bool f<T,T1,T2,TL>( T root, Func<T,T1> p1, Func<T1,T2> p2, Func<T2,TL> plast,
Func<TL, bool> comp) where T:class where T1:class where T2:class
{
var allbutLast = f1(f1(root, p1), p2);
return allbutLast != null && comp(plast.Invoke(allbutLast));
}
Usage
var m = new Model();
if (f(m, p => p.Bids, p => p.Items, p => p.Count, p => p > 0))
{
Debug.WriteLine("f");
}
if (tc(() => m.Bids.Items.Count > 0))
{
Debug.WriteLine("tc ");
}
if (m.Bids != null && m.Bids.Items != null && m.Bids.Items.Count > 0)
{
Debug.WriteLine("plain");
}