zaphoyd / websocketpp

C++ websocket client/server library
http://www.zaphoyd.com/websocketpp
Other
7.06k stars 1.98k forks source link

How to send message::data_ptr payload? #134

Open bigfans opened 12 years ago

bigfans commented 12 years ago

Hi, everybody! I am a beginner of websocketpp. It's really a wonderful lib. I got some questions while using it in my research. (1) How to send binary data ? (2) How to use websocket::connection::send(message::data_ptr msg) function ? (3) Is there a specific manual for websocketpp ?

Many THANKS!

zaphoyd commented 12 years ago

1) The simplest way is to use send(const std::string& payload, websocketpp::frame::opcode::value op)

this will send the contents of payload using the websocket opcode op. op defaults to text, but a binary message can be sent by substituting the opcode websocketpp::frame::opcode::BINARY

2) websocketpp v0.2 uses message::data_ptr as a buffer to store incoming and outgoing messages. The buffer stores the actual message contents as well as some message state like the opcode to use, extension data, and internal bookkeeping data.

send(message::data_ptr msg) will push a pointer to that message into the send queue.

Its usage:

message::data_ptr msg = con->get_data_message(); msg->reset(message::frame::opcode::TEXT); // or message::frame::opcode::BINARY msg->set_payload(std::string); msg->append_payload(std::string); con->send(msg);

After calling con->send(message::data_ptr) you should not modify msg and for best performance should delete the pointer as soon as possible. You may call send on the msg multiple times (for example to broadcast the same message to multiple clients). Doing so is significantly more efficient in terms of memory than individual sends.

3) websocketpp is still in development so things are changing just a little too often for a usage manual just yet. For the moment there are examples in the examples section of the code and some api reference http://www.zaphoyd.com/websocketpp/docs/. Feel free to ask any other questions here.

bigfans commented 12 years ago

First of all, i use Visual C++ 2010 as my compiler and IDE.

1) In WB++ src, the send function use std::string as its parameter type (so does the message::data's set_payload function). In WB++ Wiki (Session API, see https://github.com/zaphoyd/websocketpp/wiki/Session-API), the send() declaration is "void send(const std::vector &);", but i can't find corresponding implemetation.

2) When i use std::string to store data with multiple '\0', it will cut off the left part following the first '\0'. Can std::string hold binary data?

3) In base64/base64.h, the encode function converts "unsigned char " to std::string, why the decode function convert encoded std::string to common std::string? (encode std::string --> unsigned char \ ?)

Thanks a lot :-)

zaphoyd commented 12 years ago

1) This was documentation for an older version of the library. Doing it that way turned out to have some irritating and performance reducing issues. It is this due to this sort of confusion that I have avoided writing a proper manual until I am happy with the API. The Doxygen documentation linked earlier for v0.2 should be current and accurate for that version, pages in the wiki may be less accurate or need version tags.

2) All constructors, mutators, and accessors of std::string have length based versions in addition to the NUL terminated ones for use with binary data. Stick to those versions of the methods and STL iterator based algorithms and you should be fine with respect to loading and removing binary data from WebSocket++ messages, including arbitrary numbers of 0x00 bytes.

3) The encode and decode functions there are definitely inconsistent. WebSocket++ and the WebSocket protocol itself never requires base64 decoding so it was probably overlooked for that reason. The base64 encoding/decoding functionality provided by WebSocket++ was implemented by a third party and the inconsistent parameters and return types are present there.

As for what to do about it now. I like the unsigned char* input for reasons of performance and flexibility and the std::string output for memory safety. I would consider changing base64_decode to accept unsigned char* as its input parameter as well. I'd rather not return unsigned char* as this would introduce a non-idiomatic C++ memory management situation. If you would like this behavior there are a number of free self contained plain C based base64 implementations.

maldworth commented 12 years ago

Hi zaphoyd, In option 2 above (your first comment), you mention "make sure you delete the pointer". When I checked the code, message::data is using boost intrusive_ptr, which as far as I can tell, once the method goes out of scope and this ptr isn't referenced outside of the method, it will be deleted (I'm assuming it's a type of smart pointer). Or did I miss something? You mention that 1 or 2 are suitable to use for binary messages. Is either one preferred by you for different situations? Thanks

zaphoyd commented 12 years ago

By delete the pointer I simply meant let it go out of scope. WebSocket++ message_ptr uses intrusive pointer to recycle the buffer when the reference count reaches 1 (ie only the library holds a copy, not the application). If your application holds on to extra copies of these buffers (like if you save them in a container somewhere or pass them to another thread) it will prevent this recycling mechanism from working.

send(message::data_ptr msg) represents the full send interface. It provides the most flexibility, but for simple messages it is a lot more to type and no more efficient.

I would use send(const std::string& msg) in general, and use send(message::data_ptr msg) in specific cases where you need more flexibility. For example:

With send(message::data_ptr msg) you can build messages in place. send(const std::string& msg) will copy all of msg into an internal buffer. If you already have your complete outgoing message in a string this is as good as you can do, but if you will be building your message in parts using append, etc doing it in a local message buffer lets you save some memory and some copying.

send(message::data_ptr msg) allows you to send a single message buffer multiple times (usually to different connections) without copying. This allows you to send n copies of a message with constant memory usage.

In WebSocket++ 0.3 (not yet released) send(message::data_ptr msg) is the only way to access some more advanced features such as whether or not the message should be compressed or fragmented.

All of these differences exist equally for binary and text messages. Binary messages are less expensive to send so the benefits of cheaper message preparation are less significant for them.

maldworth commented 12 years ago

Wow that was a fast response. Thank you so much for the detailed use cases of each send(...)!

rcampbell88 commented 10 years ago

After I do a connection to a socket, how do I know if the connection succeeded and is all the header information required for a websocket connection sent to the connected end? I am trying to build a client which sends and receives JSON messages.

I took the code from testee_client.cpp and incorporated it into my own client and did the connection but I am not sure if the connection succeeded or not.

zaphoyd commented 10 years ago

If you register an open handler with your endpoint it will be called once for each connection when the connection successfully opens. Likewise, the fail handler is called in the case when the connection fails.

unphased commented 10 years ago

I have a little question that may be (slightly) relevant to this topic. I always thought a websocket connection was either binary or text, but it sure looks here like each message can be sent one way or another.

Is it simply that the (browser) client may barf on it at will, but that the web socket spec/implementation allows for this extra flexibility?

rcampbell88 commented 10 years ago

The web socket is nothing more than a full duplex TCP connection. I actually created my own web socket, all you have to do is send the correct strings and then the socket is just TCP and can send and receive like any other TCP connection. I also have a question for you, what happens in your library when the message it is trying to parse contains a field it does not know about?

Date: Thu, 20 Mar 2014 21:17:07 -0700 From: notifications@github.com To: websocketpp@noreply.github.com CC: campbell_ray@hotmail.com Subject: Re: [websocketpp] How to send message::data_ptr payload? (#134)

I have a little question that may be (slightly) relevant to this topic. I always thought a websocket connection was either binary or text, but it sure looks here like each message can be sent one way or another.

Is it simply that the (browser) client may barf on it at will, but that the websocket spec allows for this extra flexibility?

— Reply to this email directly or view it on GitHub.

unphased commented 10 years ago

Good point! You're making it sound like a dumb question. Ha!

Websocket++ is awesome.

zaphoyd commented 10 years ago

Once established, you can send and receive both UTF8 text and Binary messages on the same WebSocket. This applies to both the browser end and the WebSocket++ end. A few older browsers (Chrome <15, FireFox <11 Safari <6) will not understand binary messages (you can use modernizr to check for binary message support).

Re: what happens when the library tries to parse data that is not correctly formatted? In most cases, per RFC6455, the connection will be terminated with an error code. Most likely 1002/Protocol Error, but occasionally a more specific one if the library was able to determine a more specific violation (bad UTF8 formatting in an otherwise correct frame, for example).

walle-z commented 6 years ago

@rcampbell88 Hi,rcampbell88 Do you realize the function of sending JSON messages through websocketpp?