sgieseking / anyrpc Goto Github PK
View Code? Open in Web Editor NEWSupport for multiple RPC protocols in a single library
License: MIT License
Support for multiple RPC protocols in a single library
License: MIT License
Hi,
AnyRpc work fine server/client on c++. But when I use it with another Server/Client on Javascript+Node on JsonHttp is still working fine. But I used with JsonTcp no data received on server.
My Javascript code (Server and Client) work fine together on jsontcp mode also, like the AnyRpc examples. But to mix or cross it that only work on JsonHttp.
The Javascript client for example is very simple like:
var client = jayson.client.tcp({port: 9000 })
client.request('add', [3.0, 5.0], function(err,response)){... throw ....}
Any idea ?
Thanks
We're using your anyrpc project to communicate to embedded devices. Assuring the devices are stilll alive we're sending a heartbeat to the device and wait for an answer. This occurs after waiting for 10ms (usually about around a second). Since we're having troubles with connection issues I recorded the TCP connection via tcpdump
on linux and attached a filtered dump file.
In detail, we're sending the string ping
to the device and are waiting for the string pong
. This usually works, but sometimes the initial initiation of the connection is included in the actual payload. Sometimes this is messed up with multiple pings.
No. Time Source Destination Protocol Length Info
52626 2327.495919 172.17.17.1 172.17.17.103 TCP 79 [TCP Retransmission] 52899 → 9000 [PSH, ACK] Seq=1298 Ack=23 Win=65536 Len=25
Frame 52626: 79 bytes on wire (632 bits), 79 bytes captured (632 bits)
Ethernet II, Src: FujitsuT_be:a8:d5 (90:1b:0e:be:a8:d5), Dst: Atmel_1f:ac:ca (fc:c2:3d:1f:ac:ca)
Internet Protocol Version 4, Src: 172.17.17.1, Dst: 172.17.17.103
Transmission Control Protocol, Src Port: 52899, Dst Port: 9000, Seq: 1298, Ack: 23, Len: 25
Source Port: 52899
Destination Port: 9000
[Stream index: 1]
[TCP Segment Len: 25]
Sequence number: 1298 (relative sequence number)
[Next sequence number: 1323 (relative sequence number)]
Acknowledgment number: 23 (relative ack number)
0101 .... = Header Length: 20 bytes (5)
Flags: 0x018 (PSH, ACK)
Window size value: 256
[Calculated window size: 65536]
[Window size scaling factor: 256]
Checksum: 0xdce8 [unverified]
[Checksum Status: Unverified]
Urgent pointer: 0
[SEQ/ACK analysis]
[iRTT: 0.000329000 seconds]
[Bytes in flight: 25]
[Bytes sent since last PSH flag: 25]
[TCP Analysis Flags]
[Expert Info (Note/Sequence): This frame is a (suspected) retransmission]
[The RTO for this segment was: 0.311942000 seconds]
[RTO based on delta from frame: 52590]
[Timestamps]
TCP payload (25 bytes)
Retransmitted TCP segment data (25 bytes)
0000 fc c2 3d 1f ac ca 90 1b 0e be a8 d5 08 00 45 00 ..=...........E.
0010 00 41 59 ea 40 00 80 06 26 42 ac 11 11 01 ac 11 .AY.@...&B......
0020 11 67 ce a3 23 28 ad 39 f5 a8 80 f9 35 23 50 18 .g..#(.9....5#P.
0030 01 00 dc e8 00 00 32 31 3a 93 02 a4 70 69 6e 67 ......21:...ping
0040 81 a1 23 82 a3 72 70 63 01 a3 63 6e 74 30 2c ..#..rpc..cnt0,
[...]
No. Time Source Destination Protocol Length Info
63651 2637.298319 172.17.17.1 172.17.17.103 TCP 101 [TCP Retransmission] 53000 → 9000 [PSH, ACK] Seq=3026 Ack=23 Win=65536 Len=47
0000 fc c2 3d 1f ac ca 90 1b 0e be a8 d5 08 00 45 00 ..=...........E.
0010 00 57 0c e2 40 00 80 06 73 34 ac 11 11 01 ac 11 [email protected]......
0020 11 67 cf 08 23 28 a0 b1 90 9b c5 c0 6b eb 50 18 .g..#(......k.P.
0030 01 00 49 8d 00 00 93 02 a4 70 69 6e 67 81 a1 23 ..I......ping..#
0040 82 a3 72 70 63 01 a3 63 6e 74 75 2c 32 31 3a 93 ..rpc..cntu,21:.
0050 02 a4 70 69 6e 67 81 a1 23 82 a3 72 70 63 01 a3 ..ping..#..rpc..
0060 63 6e 74 76 2c cntv,
[...]
No. Time Source Destination Protocol Length Info
72268 2724.402597 172.17.17.1 172.17.17.103 TCP 105 [TCP Retransmission] 53020 → 9000 [PSH, ACK] Seq=25610 Ack=23 Win=65536 Len=51
0000 fc c2 3d 1f ac ca 90 1b 0e be a8 d5 08 00 45 00 ..=...........E.
0010 00 5b 68 69 40 00 80 06 17 a9 ac 11 11 01 ac 11 .[hi@...........
0020 11 67 cf 1c 23 28 12 38 3e a8 27 93 71 f2 50 18 .g..#(.8>.'.q.P.
0030 01 00 a6 eb 00 00 93 02 a4 70 69 6e 67 81 a1 23 .........ping..#
0040 82 a3 72 70 63 01 a3 63 6e 74 cd 03 bf 2c 32 33 ..rpc..cnt...,23
0050 3a 93 02 a4 70 69 6e 67 81 a1 23 82 a3 72 70 63 :...ping..#..rpc
0060 01 a3 63 6e 74 cd 03 c0 2c ..cnt...,
Do you see any chance this might be caused in the anyrpc project? It looks like someone is not sending, but filling the send-buffer multiple times.
hi,
I try to build your lib again. But now the compilation failed. Maybe after your last merge (24/01/2017). why you did not use a Branch or Tag to keep the old version code and the new with the modifications.
std::condition_variable condVarDelayedRemove_;
^
/data/IPC_TESTS/anyrpc/src/method.cpp: In member function ‘bool anyrpc::MethodManager::RemoveMethod(const string&, bool)’:
/data/IPC_TESTS/anyrpc/src/method.cpp:114:17: error: ‘condVarDelayedRemove_’ was not declared in this scope
condVarDelayedRemove_.wait(lock);
^
/data/IPC_TESTS/anyrpc/src/method.cpp: In member function ‘void anyrpc::MethodManager::ExecuteMethod_FollowUpOperations(anyrpc::Method*)’:
/data/IPC_TESTS/anyrpc/src/method.cpp:167:9: error: ‘condVarDelayedRemove_’ was not declared in this scope
condVarDelayedRemove_.notify_all(); // notify waiting calls of remove method (if any)
^
make[2]: *** [src/CMakeFiles/anyrpc.dir/method.cpp.o] Error 1
make[1]: *** [src/CMakeFiles/anyrpc.dir/all] Error 2
make: *** [all] Error 2
Hi,
I've run into a threading issue with the method manager, which was hard to find but can easily be forced to occur. First I'll give a short description how to reproduce the error, afterwards I'll explain and give my thoughts.
Reproduction
exampleServer
and exampleClient
from anyrpc examples. I used the single threaded JsonTcpServer, but the error probably occurs for all threaded servers.ExecuteMethod
like this: [...]
if (it == methods_.end())
return false;
std::cout << "MethodManager paused..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(15));
std::cout << "MethodManager going on." << std::endl;
it->second->Execute(params,result);
[...]
this_thread::sleep_for( chrono::seconds(timeout) );
to the following lines: this_thread::sleep_for( chrono::seconds(10) );
std::cout << "Remove subtract now..." << std::endl;
methodManager->RemoveMethod("add");
std::cout << "Server changes finished." << std::endl;
this_thread::sleep_for(chrono::seconds(30));
std::cout << "Server shutting down..." << std::endl;
Explanation and Thoughts
Inside the server's worker thread incoming rpc-commands from client are directed to the ExecuteMethod function. However this access is not protected by any mutex, so nothing prevents the main thread (or any other thread) from accessing MethodManager. By adding the sleep in ExecuteMethod, I'm just "increasing" the possibility of a thread-change at this point.
If at this point the RemoveMethod function is called from main thread, the issue is obvious. The iterator is invalidated (and besides we do not have the corresponding function that should be executed anymore).
Note, that this issue does occur for any MethodManager function, because they all use iterators which might be invalidated. However (if I see this correctly) the invalidation does only occur for RemoveMethod. In AddMethod this issue does not occur, because a map is used and map-iterators aren't invalidated on insertion (unlike e.g. vectors). Still you could think of other problems, like adding multiple methods at the same time, listing and adding at the same time, ...
In general I would propose the usage of a mutex, which prevents from multiple access to any of the member functions, but I wanted to hear your oppinion first. The following problems might occur:
Any comments on these topics?
PS: I'm aware that the RemoveMethod function was added by one of my pull requests, but without it one would reactivate the problem of deleted references (discribed in #24).
I've checked out the current master and compiled on Win7 with VS2015. In the exampleServer.cpp I've changed the Add function:
void Add(Value& params, Value& result)
{
result.SetMap();
result["value"] = 0;
result["text"] = "";
std::cout << result << std::endl;
}
Now calling from command line with
start anyrpc\build\bin\Debug\exampleServer.exe jsontcptp 9000 10
start anyrpc\build\bin\Debug\exampleClient.exe jsontcp 127.0.0.1 9000
on client side I get as expected the result
success: 1, add: {"value":0,"text":""}
Using
start anyrpc\build\bin\Debug\exampleServer.exe messagepacktcptp 9000 10
start anyrpc\build\bin\Debug\exampleClient.exe messagepacktcp 127.0.0.1 9000
The bug is probably related to using 0 as a value, but I'm not sure why.
Hi,
I'm using the Client::Notify()
functionality to send some strings to my Json-Tcp-server (I'm using a threadpool, but the behaviour is the same for single thread). On the server these strings are just printed to std::cout
. Doing this I could observe the following behaviour: Sometimes not all messages are printed, but just the first x messages. When sending more messages later, first the missing messages are printed and the new ones are missing... This goes on and the amount of missing messages grows, but this growth is not constant.
Running in the debugger, I could track down the issue: In class Connection
on the server, the member variable buffer_
contains all the missing messages, so it's not a problem of the tcp-connection. If I understand the purpose of the code correctly, the problem is in function Connection::Process()
. For notifications one never gets the state WRITE_RESPONSE
so newMessage will be false even if other messages are in buffer.
I'm now using the hotfix
// When operating a thread pool, the main thread might need to continue
// to write a long response to the socket after the connection is returned
if (connectionState_ == WRITE_RESPONSE)
{
if (!WriteResponse())
{
connectionState_ = CLOSE_CONNECTION;
break;
}
}
// Check if additional messages should be processed
newMessage = (connectionState_ == READ_HEADER) && (bufferLength_ > 1);
but I'm not totally sure if this is the correct fix. After all I had to use bufferLength_ >1
instead of >0
because otherwise one would have a infinite loop (in debugger bufferLength_ is 1 if no messages are left in the buffer, why so?). However this loop would also appear for Call(), but I'm really not sure why...
Hello,
I'm using the AnyRPC under Win7 with Visual Studio 2015. The target application shall be compiled for 32bit and 64bit. During compilation some warnings of this kind occur:
warning C4267: 'var' : conversion from 'size_t' to 'type', possible loss of data
Under 32bit it's only 'size_t' to 'char' having problems, and the position in code can easily be handled with a simple static_cast. However, under 64bit it's also 'size_t' to 'int', 'size_t' to 'uint32_t' and others. Most of the calls refer to arguments passed between different string functions.
Example:
//! Copy the string as either a short string or with allocated memory.
void CopyString(const char* s) { CopyString(s, strlen(s)); }
//! Copy the string as either a short string or with allocated memory.
void CopyString(const char* s, int length);
strlen(s) returns a size_t, while CopyString takes an int.
Does the anyrpc library fully support 64 bit or might I run into problems later on? Any hints / comments on how to solve this warning in a most appropriate way?
Hi @sgieseking,
thanks again for your support in my recent issues. This issue is more of a question and not really a problem:
When dealing with the Method-class
//! A MethodFunction is created with a function pointer that is call by the Execute method.
class MethodFunction : public Method
{
public:
MethodFunction(Function* function, std::string const& name, std::string const& help, bool deleteOnRemove=true) :
Method(name, help, deleteOnRemove), function_(function) {}
virtual void Execute(Value& params, Value& result) { if (function_) function_(params, result); }
private:
Function *function_;
};
I was wondering, if there would be any problem with making the "params" input of the Execute method constant:
virtual void Execute(const Value& params, Value& result)
If I see it correctly, params should never be changed by Execute, so this would lead to a more readable function body and self explaining code. It would require more changes to const in other functions (e.g. MethodManager::ListMethods), but I don't see any counter-argument.
After all, you have the better understanding of your class, so maybe you could tell me if I missed any point against this.
Thanks
Jan
Hi, I'm not quite sure about this problem and the best way to solve it, that's why I have created an issue instead of a pull-request.
Similar to the exampleServer, I might create a method like this:
class Multiply : public Method
{
public:
Multiply() : Method("multiply", "Multiply two numbers",true) {};
virtual void Execute(Value& params, Value& result) { // something}
};
Having set deleteOnRemove to "true", the deletion of the object shall be handled by AnyRpc.
Now suppose having a correct working server, I use it like this:
[...]
server->GetMethodManager()->AddMethod( new Multiply );
[...]
server->GetMethodManager()->AddMethod( new Multiply );
[...]
By this we would create a memory leak, wouldn't we?
Looking at
void MethodManager::AddMethod(Method* method)
{
MethodMap::const_iterator it = methods_.find(method->Name());
if (it == methods_.end())
// not found so add new method
methods_[method->Name()] = method;
}
the second call would not go into the if branch, which leads to pointer beeing lost without destroying the memory.
Of course the example does not make much sense, but I'm thinking about bigger projects. Between the two AddMethod calls might be a lot of stuff, they might even be called from different source files. It even has not to be the same class which is added, if I see it correctly only the "name" of the method is relevant.
I see the following solution:
void MethodManager::AddMethod(Method* method)
{
MethodMap::const_iterator it = methods_.find(method->Name());
if (it == methods_.end())
{
// not found so add new method
methods_[method->Name()] = method;
}
else
{
// some error-message???
if method->DeleteOnRemove()
delete method;
}
}
I'm not sure if this is the best solution or if it handles all possible cases. One might also think about usage of unique_ptr. Any thoughts on this problem?
I'm using anyrpc as a c++ RPC server and xmlrcp as a python client.
When I send a unicode string using xmlrcp, the string is sent with the UTF8 bytes (for exemple "ā" is sent as 0xC4 0x81 (which is -60, -127 in char).
Maybe this is an error from xmlrcp not to convert the UTF8 bytes to escaped xml characters like expected by anyrpc (&#C4Q I guess?), but anyway the software shall not crash when receiving this data.
The error is in Reader::IsWhiteSpace
, it uses std::isspace which does not support negative signed char, see the official documentation: https://en.cppreference.com/w/cpp/string/byte/isspace
XmlRpc.net will send <params />
when there is no parameters.
But AnyRPC can't parse it and return parse error.
For example:
<!-- Request -->
<?xml version="1.0"?>
<methodCall>
<methodName>
MethodName
</methodName>
<params/>
</methodCall>
<!-- Response -->
<?xml version="1.0" encoding="utf-8"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>
faultCode
</name>
<value>
<i4>
-32700
</i4>
</value>
</member>
<member>
<name>
faultString
</name>
<value>
Parse error
</value>
</member>
</struct>
</value>
</fault>
</methodResponse>
Hi again,
I just noticed, that you call WSAStartup in Socket() constructor if compiling for WIN32 (socket.cpp). However you never call WSACleanup, which should be done according to Microsoft:
An application must call the WSACleanup function for every successful time the WSAStartup function is called. This means, for example, that if an application calls WSAStartup three times, it must call WSACleanup three times. [source]
Do I miss something or is this a bug?
If I understand the Microsoft documentation correctly, you could just call WSAStartup in every constructor (not guarded by the wsInit) and similarly the WSACleanup in Destructor and everything would be fine.
Greatings
Jan
Hi,
on my messagepack TCP-server I've added the method
class Print : public anyrpc::Method
{
public:
Print() : Method("print", "Print given information.", true) {};
virtual void Execute(anyrpc::Value& params, anyrpc::Value& result)
{
if (params.IsString())
{
std::string sTemp(params.GetString());
std::cout << sTemp;
}
result = true;
}
};
On my client I'm calling
std::string ten("123456789_");
std::string fifty(ten+ten+ten+ten+ten);
std::string temp(fifty+fifty+ten+ten+"12345678");
anyrpc::Value param(temp), result;
myClient->Notify("print",param, result);
When receiving this message on the server, I get the errors
I changed the length of the string and for me all strings of length <=127 are working. So it seems, that (2^7)-1 is the maximum lenth of a transmitted string. Is this on purpose or a bug?
Looking into the msgpack specification ( https://github.com/msgpack/msgpack/blob/master/spec.md#str-format-family ) I would expect that a maximum length of (2^32)-1 is supported. Or, if only str 8 is implemented at least (2^8)-1...
Using a JSON server and client instead, the same code works fine even with strings of length 1000 and more.
I'm using anyrpc as a c++ RPC server and xmlrcp as a python client.
xmlrpc send a pretty xml with a newline character before/after each tag.
But if the base64 string is padded (ends with = or ==) anyrpc always expects the next tag to be just after the end of the base64 string.
See Base64Decode
method:
// verify termination character
return (is.Peek() == termChar);
Hi,
while developing multi-thread applications naming of threads (e.g. for debugging) has proven to be quite useful. In the following I'd like to propose some additions to your library. Use them if you like them, feel free to simply close this issue if you think otherwise...
Header threadName.h would be:
#ifndef THREAD_NAME_H_
#define THREAD_NAME_H_
#include <thread>
namespace misc
{
/// name current thread
void SetThreadName(const std::string& threadName);
/// name thread identified by thread-handle
void SetThreadName(std::thread& thread, const std::string& threadName);
}
#endif /* THREAD_NAME_H_ */
Source threadName.cpp would be the following, where the windows part is mainly based on this MSDN example (it appears "dirty", but I didn't find any cleaner solution):
#include "anyrpc/threadName.h"
#ifdef _WIN32 /* WINDOWS */
#include <windows.h>
const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
void SetThreadName(DWORD dwThreadID, const char* threadName) {
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = threadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
#pragma warning(push)
#pragma warning(disable: 6320 6322)
__try
{
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
#pragma warning(pop)
}
namespace misc
{
void SetThreadName(const std::string& threadName)
{
::SetThreadName(GetCurrentThreadId(), threadName.c_str());
}
void SetThreadName(std::thread& thread, const std::string& threadName)
{
DWORD threadId = ::GetThreadId(static_cast<HANDLE>(thread.native_handle()));
::SetThreadName(threadId, threadName.c_str());
}
}
#else /* LINUX */
#include <sys/prctl.h>
namespace misc
{
void SetThreadName(const std::string& threadName)
{
::prctl(PR_SET_NAME, threadName.c_str(), 0, 0, 0);
}
void SetThreadName(std::thread& thread, const std::string& threadName)
{
auto handle = thread.native_handle();
::pthread_setname_np(handle, threadName.c_str());
}
}
#endif
Obviously this is not for MacOS yet...
Using the above header and source one could for example add this line to StartThread()
in server.cpp:
misc::SetThreadName(thread_, "AnyRpcServer");
Adding such a line to all thread creations allows an easy recognition of different threads in a multi-thread-environment and also thread-name-dependent breakpoints (the latter at least in VS).
Hi,
I'm launching the exampleServer and exampleClient provided with this project and compiled with gcc under RHEL 7.0 by these command line calls:
build/bin/exampleServer jsontcp 9000 9000
buid/bin/exampleClient
If I run the client program for 100 times, the server response correctly. However, the file descriptor occupied by the exampleServer is keep growing, which can launch following command line:
ll /proc/$(pidof exampleServer)/fd
So If I want to open another file such a plain text file by rpc call, I may fail to open the file since the file descriptor is all occupied after many rpc call.
I wonder when the server will close the file descriptor ( socket fd ).
How can I solve this problem?
Have you guys considered adding an option to use INADDR_LOOPBACK instead of INADDR_ANY in Socket::Bind()
? The latter binds to 0.0.0.0 which triggers firewalls, while the loopback option binds to the local address without additional firewall attention.
I'm using this library as a part of Spix project, which is UI automation library and all the network communication is done locally on the host, so those firewall's notifications are quite annoying. It would be really nice to have a "local only" option somewhere in AnyRPC please :)
Thank you.
Hi,
I'm launching the exampleServer and exampleClient provided with this project and compiled with VisualStudio 2015 under Win7 64bit by these command line calls:
start anyrpc\build\bin\Debug\exampleServer.exe jsontcp 9000 100
start anyrpc\build\bin\Debug\exampleClient.exe jsontcp 127.0.0.1 9000
At the moment the client finishes its job, the server displays the following warning:
In my own project, I noticed that this warning always occurs, if a Jsontcp-client calls the close() function. It's probably not even related to the target system and compiler, because it also happens on linux with gcc.
Are you able to reproduce this warning?
We're using the tcp-messagepack implementation of anyrpc with enabled threading.
Upon system shutdown we're closing down the connections and sometimes it happens that select() hangs up. This can be identified using the remote debugger for ARM. We're using a timeout of 100 ms.
Furthermore, using the variable _threadRunning
as of type bool
is not threadsafe and should be implemented as std::atomic
.
A possible workaroung might be to look at signals for the usage with select()
.
http://man7.org/linux/man-pages/man2/select_tut.2.html
Has anyone considered this solution?
Is there any way to "unbind" a anyrpc::server for TCP without destroying it?
Background: I've a server with some attached methods. Now I would like to stop the server, so it does not listen on any port for a while. Afterwards I would like to bind it again, depending on other information to the same or another port.
Is this possible? If yes, how do I do it?
Of course one could destroy the old and initialize a totally new server, but then all attached methods have to be bound again. I'd like to avoid this.
What I've tried:
I've called StopThread(), Exit(), Shutdown() on the server but still a call of BindAndListen() leads to:
"Could not bind to spedified port: -1".
I've tried to track the error further down, but the usage of sockets in general and in this library in particular remains kind of unclear to me. After all I do not really know when to use StopThread(), Exit() and Shutdown() and in which order. Any hint on that?
Thanks again for your great library. I see, that my problem might be a little special, but I hope that you can still give some information or point me in the right direction.
What do you think about an additional function template for value.h?
//! Add member with string and any type known by value-constructor
template<typename T>
Value& Add2Map(const std::string& str, T& value) { Value tempValue(value); return AddMember(str.c_str(), str.length(), tempValue); }
Supposed the corresponding variables myString, myInt, myBool exist, instead of calls like
anyrpc::Value param(anyrpc::ValueType::MapType)
anyrpc::Value newMember;
newMember = anyrpc::Value( myString );
param.AddMember("print",newMember);
newMember = anyrpc::Value( myInt );
param.AddMember("number",newMember);
newMember = anyrpc::Value( myBool );
param.AddMember("boolean",newMember);
one could use
anyrpc::Value param(anyrpc::ValueType::MapType)
param.Add2Map("print",myString);
param.Add2Map("number",myInt );
param.Add2Map("boolean",myBool );
with the above function template. This occurs quite often for me.
Or is there any better way?
Hello @sgieseking,
I have successfully compiled the anyrpc examples with log4cplus on Windows with Visual Studio 2015.
The examples are running fine and the logging is working.
But the application crashes on exit.
I found an issue on the log4cplus project page having the same error. However I was not able to use this information to eliminate the crash.
Simply adding log4cplus::Initializer initializer;
to the top of the main of exampleServer
does not fix the error.
Can you give me a few pointers how the error can be corrected?
Thank you in advance for your time and help.
Greetings
Jan
Hi,
if I figured it correctly, anyrpc-logging is not working with unicode enabled.
Log4cplus itself supports unicode, for example I was building (on Win7 64bit, VS2015) with
cmake -DBUILD_SHARED_LIBS:BOOL=TRUE -DWITH_UNIT_TESTS=OFF -DLOG4CPLUS_BUILD_TESTING=OFF -DUNICODE=ON -DLOG4CPLUS_BUILD_LOGGINGSERVER=OFF -DLOG4CPLUS_SINGLE_THREADED=ON
However setting up anyrpc via
cmake -DBUILD_EXAMPLES=OFF -DBUILD_WITH_LOG4CPLUS=ON -DBUILD_WITH_WCHAR=ON -DBUILD_WITH_THREADING=ON -DUNICODE=ON -DLOG4CPLUS_LIBRARY_RELEASE=....\log4cplus\build\src\Release\log4cplusU.lib -DLOG4CPLUS_LIBRARY_DEBUG=....\log4cplus\build\src\Debug\log4cplusUD.lib
leads to a project file, that can't be compiled (note that I provided the correct libs from log4cplus, however you might need to manually add the UNICODE preprocessor define to anyrpc project).
When compiling the anyrpc-project one gets multiple errors like
binary operator '<<': no operator found which takes a right-hand operand of type 'std::string' (or there is no acceptable conversion)
or
'TimeLogger::TimeLogger(const TimeLogger &)' : cannot convert argument n from 'const char [1]' to 'log4cplus::tstring &'.
These errors are caused by calling log4cplus-macros, which obviously expect wchar (or corresponding strings) when compiled with UNICODE-preprocessor define. However the calls by anyrpc are done with simple chars, often fixed strings like "this is an example"
.
One solution for this problem would be, to use something like TCHAR
and _T("my example")
(these two only exist in Visual Studio as far as I know), but one would need to change all the logs accordingly.
For myself I found another "solution": In fact I don't really want unicode-logging, but I need the unicode-define enabled in my main project, because it is working with QT and QT needs unicode. So I just compile the dlls for anyrpc & log4cplus without UNICODE-preprocessor defined. In order to include correct headers in my main project, I changed the following lines in logger.h:
# ifdef UNICODE
# undef UNICODE
# define UNICODE_DISABLED_BECAUSE_ANYRPC_LOGGING_WITH_UNICODE_NOT_SUPPORTED
# endif
# include <log4cplus/log4cplus.h>
# define InitializeLogger() \log4cplus::Initializer initializer; \ log4cplus::PropertyConfigurator config(LOG4CPLUS_TEXT("log4cplus.properties")); \ config.configure();
# ifdef UNICODE_DISABLED_BECAUSE_ANYRPC_LOGGING_WITH_UNICODE_NOT_SUPPORTED
# undef UNICODE_DISABLED_BECAUSE_ANYRPC_LOGGING_WITH_UNICODE_NOT_SUPPORTED
# define UNICODE
# endif
Obviously this is neither the cleanest nor a general solution, but this way UNICODE is defined everywhere (where QT needs it) except for the anyrpc / log4cplus part.
Any comments on this topic? Maybe I missed a point or there is a better way to get anyrpc running with unicode?
I send a long Base64 String in a xmlrpc from an anyrpc Server. The Server is on an embedded device (armv7l 32 bit processor.).
In my Python xmlrpc Client I get the following error message: xml.parsers.expat.ExpatError: no element found: line 2, column 25948
I try to use curl, but I get : curl: (18) transfer closed with 21434 bytes remaining to read
On Stack Overflow the mention it could be the `Content-Length. So I try to bring up the ContentLength in the Code. But the error peers.
Does anyone have an idea to solve this problem?
I see #48 there is a similar Problem with base64 and xmlrpc, but I think this is not the same problem.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.