- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试为我的应用程序评估使用异步提升 udp/tcp 套接字操作与同步操作。我一直在努力寻找一个与我的设计相似的示例,但没有找到任何让我相信我可能正在尝试将异步操作融入我的设计的东西,即使它不是正确的路径。
我想连接到多个(读取:1-10 个之间)服务器并使用不同的协议(protocol)与它们通信;我有 4-5 个线程正在生成需要与这些服务器连接中的任何一个通信的数据。
我当前的设计是同步的,每个服务器连接线程使用一个 io_service
对象,然后在生产线程和每个连接线程之间使用一个线程安全队列。
这种设计在吞吐量性能方面似乎不可扩展,这是我想最大化的。
是否有任何示例可以提供这种到不同服务器模式的多个连接?
最佳答案
我已经编写了一个客户端来使用 TCP/IP SSL/TLS 连接到 6 个不同的服务器,这是通过 ASIO 实现的。所有 6 个都使用相同的协议(protocol)。所以,如果有帮助,这是我的代码:
SSLSocket.H
#pragma once
#include <cstdlib>
#include <iostream>
#include <queue>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/shared_ptr.hpp>
using namespace std;
//
#include "BufferManagement.h"
#include "Logger.h"
#include "Common Classes\Locking.h"
#include "Message.h"
class SSLSocket;
class ConcurrentMsgQueue;
#define BOOST_ASIO_ENABLE_HANDLER_TRACKING
typedef void (__stdcall *Callback)(const SSLSocket* pSSLS, const int bytesInMsg, const void* pBuf);
// typedef std::vector<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SocketVectorType;
enum {MsgLenBytes = 4};
class SSLSocket
{
// This class handles all communications between the client and the server
// using TCP/IP SSL v1. The Boost ASIO (Asynchronous I/O) library is used to accomplish this.
// Initally written by Bob Bryan on 1/21/2013.
//
public:
SSLSocket(const bool logToFile, const bool logToConsole, const bool displayInHex, const LogLevel levelOfLog, const string& logFileName, const int bufMangLen);
~SSLSocket();
void Connect(SSLSocket* psSLS, const string& serverPath, string& port);
void SendToServer(const int bytesInMsg, Byte* pBuf);
void Stop();
static void SetCallback(Callback callbackFunction)
{
// This method is required in order to be able to do a reverse pinvoke from C#.
// This callback function pointer is what is used to communicate back to the C# code.
CallbackFunction = callbackFunction;
}
static Byte* AllocateMem(int length)
{
// Allocate some memory. This method winds up getting called when the C# client needs to allocate some memory for a message.
Byte* pBuf = BufMang.GetPtr(length);
return pBuf;
}
//
static Logger Log; // Object used to log info to a file and/or to the console.
static Callback CallbackFunction; // Callback function object used to communicate with the worker thread in C#.
private:
void InitAsynchIO();
void HandleConnect(const boost::system::error_code& error);
void HandleHandshake(const boost::system::error_code& error);
void HandleFirstWrite(const boost::system::error_code& error, size_t bytes_transferred);
void HandleRead(const boost::system::error_code& error, size_t bytesTransferred);
// void HandleRead(const boost::system::error_code& error, size_t bytes_transferred);
void Terminate();
void static RcvWorkerThread(SSLSocket* sSLS);
void static SendWorkerThread(SSLSocket* psSLS);
void ProcessSendRequests();
void HandleWrite(const boost::system::error_code& error, size_t bytesTransferred);
static void WorkerThread(boost::shared_ptr< boost::asio::io_service > io_service);
//
struct Bytes
{
// Used to convert 4 bytes to an int.
unsigned char B1;
unsigned char B2;
unsigned char B3;
unsigned char B4;
};
union Bytes4ToInt
{
// Converts 4 bytes to an int.
int IntVal;
Bytes B;
};
inline int BytesToInt(const Byte * pBuf)
{
// This method converts 4 bytes from an array of bytes to a 4-byte int.
B2I.B.B1 = *pBuf++;
B2I.B.B2 = *pBuf++;
B2I.B.B3 = *pBuf++;
B2I.B.B4 = *pBuf;
int Value = B2I.IntVal;
return Value;
}
//
boost::thread_group WorkerThreads; // Used to handle creating threads.
CRITICAL_SECTION SocketLock; // Used in conjuction with the Locking object to handle single threading the code.
boost::asio::ssl::stream<boost::asio::ip::tcp::socket>* pSocket; // Pointer to the socket object.
Bytes4ToInt B2I; // Used to translate 4 bytes in the buffer to an int representing the number of bytes in the msg.
std::string sClientIp; // Client IP address. Used for logging.
unsigned short uiClientPort; // Port number. Used for logging.
// static MessageList* pRepMsgs; // Link list of the msgs to send to the server.
Byte* pDataBuf; // Pointer to the data for the current message to be read.
static boost::shared_ptr< boost::asio::io_service > IOService; // Object required for use by ASIO to perform certain functions.
static bool RcvThreadCreated; // Set when the rcv thread is created so that it won't try to create it again.
static int StaticInit; // Indicates whether or not the static members have been initialized or not.
static bool DisplayInHex; // Specifies whether to display a buffer in hex or not.
static BufferManagement BufMang; // Smart pointer to the buffer used to handle requests coming to and from the server for all sockets.
volatile static bool ReqAlive; // Used to indicate whether the request thread should die or not.
// static bool RepAlive; // Used to indicate whether the response thread should die or not.
static ConcurrentMsgQueue SendMsgQ; // Holds the messages waiting to be sent to the server.
static HANDLE hEvent; // Used for signalling between threads.
};
SSLSocket.cpp
#include "StdAfx.h"
#include "SSLSocket.h"
boost::shared_ptr< boost::asio::io_service > SSLSocket::IOService;
int SSLSocket::StaticInit = 0;
Callback SSLSocket::CallbackFunction;
BufferManagement SSLSocket::BufMang;
volatile bool SSLSocket::ReqAlive = true;
Logger SSLSocket::Log;
HANDLE SSLSocket::hEvent;
bool SSLSocket::DisplayInHex;
ConcurrentMsgQueue SSLSocket::SendMsgQ;
bool SSLSocket::RcvThreadCreated = 0;
BufferManagement* Message::pBufMang;
SSLSocket::SSLSocket(const bool logToFile, const bool logToConsole, const bool displayInHex,
const LogLevel levelOfLog, const string& logFileName, const int bufMangLen) : pSocket(0)
{
// SSLSocket Constructor.
// If the static members have not been intialized yet, then initialize them.
if (!StaticInit)
{
DisplayInHex = displayInHex;
BufMang.Init(bufMangLen);
Message::SetBufMang(&BufMang);
// This constructor enables logging according to the vars passed in.
Log.Init(logToFile, logToConsole, levelOfLog, logFileName);
// Create the crit section object
// Locking::InitLocking(ReadLock);
// Locking::InitLocking(WriteLock);
StaticInit++;
hEvent = CreateEvent(NULL, false, false, NULL);
// Define the ASIO IO service object.
// IOService = new boost::shared_ptr<boost::asio::io_service>(new boost::asio::io_service);
boost::shared_ptr<boost::asio::io_service> IOServ(new boost::asio::io_service);
IOService = IOServ;
}
}
SSLSocket::~SSLSocket(void)
{
delete pSocket;
if (--StaticInit == 0)
CloseHandle(hEvent);
}
void SSLSocket::Connect(SSLSocket* psSLS, const string& serverPath, string& port)
{
// Connects to the server.
// serverPath - specifies the path to the server. Can be either an ip address or url.
// port - port server is listening on.
//
try
{
Locking CodeLock(SocketLock); // Single thread the code.
// If the user has tried to connect before, then make sure everything is clean before trying to do so again.
if (pSocket)
{
delete pSocket;
pSocket = 0;
}
// If serverPath is a URL, then resolve the address.
// Note that this code expects the first server to always have a url.
if ((serverPath[0] < '0') || (serverPath[0] > '9')) // Assumes that the first char of the server path is not a number when resolving to an ip addr.
{
// Create the resolver and query objects to resolve the host name in serverPath to an ip address.
boost::asio::ip::tcp::resolver resolver(*IOService);
boost::asio::ip::tcp::resolver::query query(serverPath, port);
boost::asio::ip::tcp::resolver::iterator EndpointIterator = resolver.resolve(query);
// Set up an SSL context.
boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client);
// Specify to not verify the server certificiate right now.
ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
// Init the socket object used to initially communicate with the server.
pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx);
//
// The thread we are on now, is most likely the user interface thread. Create a thread to handle all incoming socket work messages.
if (!RcvThreadCreated)
{
WorkerThreads.create_thread(boost::bind(&SSLSocket::RcvWorkerThread, this));
RcvThreadCreated = true;
WorkerThreads.create_thread(boost::bind(&SSLSocket::SendWorkerThread, this));
}
// Try to connect to the server. Note - add timeout logic at some point.
boost::asio::async_connect(pSocket->lowest_layer(), EndpointIterator,
boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error));
}
else
{
// serverPath is an ip address, so try to connect using that.
//
// Create an endpoint with the specified ip address.
const boost::asio::ip::address IP(boost::asio::ip::address::from_string(serverPath));
int iport = atoi(port.c_str());
const boost::asio::ip::tcp::endpoint EP(IP, iport);
// Set up an SSL context.
boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client);
// Specify to not verify the server certificiate right now.
ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
// Init the socket object used to initially communicate with the server.
pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx);
//
// Try to connect to the server. Note - add timeout logic at some point.
//pSocket->core_.engine_.do_connect(void*, int);
// pSocket->next_layer_.async_connect(EP, &SSLSocket::HandleConnect)
// pSocket->next_layer().async_connect(EP, &SSLSocket::HandleConnect);
boost::system::error_code EC;
pSocket->next_layer().connect(EP, EC);
if (EC)
{
// Log an error. This worker thread should exit gracefully after this.
stringstream ss;
ss << "SSLSocket::Connect: connect failed to " << sClientIp << " : " << uiClientPort << ". Error: " << EC.message() + ".\n";
Log.LogString(ss.str(), LogError);
}
HandleConnect(EC);
// boost::asio::async_connect(pSocket->lowest_layer(), EP,
// boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error));
}
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::Connect: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
void SSLSocket::SendToServer(const int bytesInMsg, Byte* pBuf)
{
// This method creates a msg object and saves it in the SendMsgQ object.
// sends the number of bytes specified by bytesInMsg in pBuf to the server.
//
Message* pMsg = Message::GetMsg(this, bytesInMsg, pBuf);
SendMsgQ.Push(pMsg);
// Signal the send worker thread to wake up and send the msg to the server.
SetEvent(hEvent);
}
void SSLSocket::SendWorkerThread(SSLSocket* psSLS)
{
// This thread method that gets called to process the messages to be sent to the server.
//
// Since this has to be a static method, call a method on the class to handle server requests.
psSLS->ProcessSendRequests();
}
void SSLSocket::ProcessSendRequests()
{
// This method handles sending msgs to the server.
//
std::stringstream ss;
DWORD WaitResult;
Log.LogString("SSLSocket::ProcessSendRequests: Worker thread " + Logger::NumberToString(boost::this_thread::get_id()) + " started.\n", LogInfo);
// Loop until the user quits, or an error of some sort is thrown.
try
{
do
{
// If there are one or more msgs that need to be sent to a server, then send them out.
if (SendMsgQ.Count() > 0)
{
Message* pMsg = SendMsgQ.Front();
SSLSocket* pSSL = pMsg->pSSL;
SendMsgQ.Pop();
const Byte* pBuf = pMsg->pBuf;
const int BytesInMsg = pMsg->BytesInMsg;
boost::system::error_code Error;
{
Locking CodeLock(SocketLock); // Single thread the code.
boost::asio::async_write(*pSSL->pSocket, boost::asio::buffer(pBuf, BytesInMsg), boost::bind(&SSLSocket::HandleWrite, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
ss << "SSLSocket::ProcessSendRequests: # bytes sent = " << BytesInMsg << "\n";
Log.LogString(ss.str(), LogDebug2);
Log.LogBuf(pBuf, BytesInMsg, DisplayInHex, LogDebug3);
}
else
{
// Nothing to send, so go into a wait state.
WaitResult = WaitForSingleObject(hEvent, INFINITE);
if (WaitResult != 0L)
{
Log.LogString("SSLSocket::ProcessSendRequests: WaitForSingleObject event error. Code = " + Logger::NumberToString(GetLastError()) + ". \n", LogError);
}
}
} while (ReqAlive);
Log.LogString("SSLSocket::ProcessSendRequests: Worker thread " + Logger::NumberToString(boost::this_thread::get_id()) + " done.\n", LogInfo);
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::ProcessSendRequests: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
void SSLSocket::HandleWrite(const boost::system::error_code& error, size_t bytesTransferred)
{
// This method is called after a msg has been written out to the socket. Nothing to do really since reading is handled by the HandleRead method.
std::stringstream ss;
try
{
if (error)
{
ss << "SSLSocket::HandleWrite: failed - " << error.message() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::HandleHandshake: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
void SSLSocket::RcvWorkerThread(SSLSocket* psSLS)
{
// This is the method that gets called when the receive thread is created by this class.
// This thread method focuses on processing messages received from the server.
//
// Since this has to be a static method, call a method on the class to handle server requests.
psSLS->InitAsynchIO();
}
void SSLSocket::InitAsynchIO()
{
// This method is responsible for initiating asynch i/o.
boost::system::error_code Err;
string s;
stringstream ss;
//
try
{
ss << "SSLSocket::InitAsynchIO: Worker thread - " << Logger::NumberToString(boost::this_thread::get_id()) << " started.\n";
Log.LogString(ss.str(), LogInfo);
// Enable the handlers for asynch i/o. The thread will hang here until the stop method has been called or an error occurs.
// Add a work object so the thread will be dedicated to handling asynch i/o.
boost::asio::io_service::work work(*IOService);
IOService->run();
Log.LogString("SSLSocket::InitAsynchIO: receive worker thread done.\n", LogInfo);
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::InitAsynchIO: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
void SSLSocket::HandleConnect(const boost::system::error_code& error)
{
// This method is called asynchronously when the server has responded to the connect request.
std::stringstream ss;
try
{
if (!error)
{
pSocket->async_handshake(boost::asio::ssl::stream_base::client,
boost::bind(&SSLSocket::HandleHandshake, this, boost::asio::placeholders::error));
ss << "SSLSocket::HandleConnect: From worker thread " << Logger::NumberToString(boost::this_thread::get_id()) << ".\n";
Log.LogString(ss.str(), LogInfo);
}
else
{
// Log an error. This worker thread should exit gracefully after this.
ss << "SSLSocket::HandleConnect: connect failed to " << sClientIp << " : " << uiClientPort << ". Error: " << error.message() + ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::InitAsynchIO: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
void SSLSocket::HandleHandshake(const boost::system::error_code& error)
{
// This method is called asynchronously when the server has responded to the handshake request.
std::stringstream ss;
try
{
if (!error)
{
// Try to send the first message that the server is expecting. This msg tells the server we want to start communicating.
// This is the only msg specified in the C++ code. All other msg processing is done in the C# code.
//
unsigned char Msg[27] = {0x17, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x41,
0x74, 0x74, 0x61, 0x63, 0x6b, 0x50, 0x6f, 0x6b, 0x65, 0x72, 0x02, 0x00, 0x65, 0x6e};
boost::system::error_code Err;
sClientIp = pSocket->lowest_layer().remote_endpoint().address().to_string();
uiClientPort = pSocket->lowest_layer().remote_endpoint().port();
ReqAlive = true;
// boost::asio::async_write(*pSocket, boost::asio::buffer(Msg), boost::bind(&SSLSocket::HandleFirstWrite, this,
// boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
int Count = boost::asio::write(*pSocket, boost::asio::buffer(Msg), boost::asio::transfer_exactly(27), Err);
if (Err)
{
ss << "SSLSocket::HandleHandshake: write failed - " << error.message() << ".\n";
Log.LogString(ss.str(), LogInfo);
}
HandleFirstWrite(Err, Count);
// boost::asio::async_write(pSocket, boost::asio::buffer(Msg, 27), boost::bind(&SSLSocket::HandleWrite, this,
// boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
ss.str("");
ss << "SSLSocket::HandleHandshake: From worker thread " << boost::this_thread::get_id() << ".\n";
}
else
{
ss << "SSLSocket::HandleHandshake: failed - " << error.message() << ".\n";
IOService->stop();
}
Log.LogString(ss.str(), LogInfo);
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::HandleHandshake: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
void SSLSocket::HandleFirstWrite(const boost::system::error_code& error, size_t bytesTransferred)
{
// This method is called after a msg has been written out to the socket.
std::stringstream ss;
try
{
if (!error)
{
// boost::asio::async_read(pSocket, boost::asio::buffer(reply_, bytesTransferred), boost::bind(&SSLSocket::handle_read,
// this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
// boost::asio::async_read(pSocket, boost::asio::buffer(reply_, 84), boost::bind(&SSLSocket::handle_read,
// this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
// Locking CodeLock(ReadLock); // Single thread the code.
// Signal the other threads that msgs are now ready to be sent and received.
// boost::asio::async_read(pSocket, boost::asio::buffer(pRepBuf), boost::asio::transfer_exactly(4), boost::bind(&SSLSocket::HandleRead,
// this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
//
// Notify the UI that we are now connected. Create a 6 byte msg for this.
pDataBuf = BufMang.GetPtr(6);
BYTE* p = pDataBuf;
// Create msg type 500
*p = 244;
*++p = 1;
CallbackFunction(this, 2, (void*)pDataBuf);
// Get the 1st 4 bytes of the next msg, which is always the length of the that msg.
pDataBuf = BufMang.GetPtr(MsgLenBytes);
// int i1=1,i2=2,i3=3,i4=4,i5=5,i6=6,i7=7,i8=8,i9=9;
// (boost::bind(&nine_arguments,_9,_2,_1,_6,_3,_8,_4,_5,_7))
// (i1,i2,i3,i4,i5,i6,i7,i8,i9);
// boost::asio::read(*pSocket, boost::asio::buffer(pReqBuf, MsgLenBytes), boost::asio::transfer_exactly(MsgLenBytes), Err);
// boost::asio::async_read(pSocket, boost::asio::buffer(pReqBuf, MsgLenBytes), boost::bind(&SSLSocket::HandleRead, _1,_2,_3))
// (this, pReqBuf, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred);
// boost::asio::async_read(*pSocket, boost::asio::buffer(reply_), boost::asio::transfer_exactly(ByteCount), boost::bind(&Client::handle_read,
// this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
// boost::asio::async_write(*pSocket, boost::asio::buffer(pDataBuf, MsgLenBytes), boost::bind(&SSLSocket::HandleWrite, this,
// boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
Locking CodeLock(SocketLock); // Single thread the code.
boost::asio::async_read(*pSocket, boost::asio::buffer(pDataBuf, MsgLenBytes), boost::bind(&SSLSocket::HandleRead, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
else
{
ss << "SSLSocket::HandleFirstWrite: failed - " << error.message() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::HandleFirstWrite: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
void SSLSocket::HandleRead(const boost::system::error_code& error, size_t bytesTransferred)
{
// This method is called to process an incomming message.
//
std::stringstream ss;
int ByteCount;
try
{
ss << "SSLSocket::HandleRead: From worker thread " << boost::this_thread::get_id() << ".\n";
Log.LogString(ss.str(), LogInfo);
// Set to exit this thread if the user is done.
if (!ReqAlive)
{
// IOService->stop();
return;
}
if (!error)
{
// Get the number of bytes in the message.
if (bytesTransferred == 4)
{
ByteCount = BytesToInt(pDataBuf);
}
else
{
// Call the C# callback method that will handle the message.
ss << "SSLSocket::HandleRead: From worker thread " << boost::this_thread::get_id() << "; # bytes transferred = " << bytesTransferred << ".\n";
Log.LogString(ss.str(), LogDebug2);
Log.LogBuf(pDataBuf, (int)bytesTransferred, true, LogDebug3);
Log.LogString("SSLSocket::HandleRead: sending msg to the C# client.\n\n", LogDebug2);
CallbackFunction(this, bytesTransferred, (void*)pDataBuf);
// Prepare to read in the next message length.
ByteCount = MsgLenBytes;
}
pDataBuf = BufMang.GetPtr(ByteCount);
boost::system::error_code Err;
// boost::asio::async_read(pSocket, boost::asio::buffer(pDataBuf, ByteCount), boost::bind(&SSLSocket::HandleRead,
// this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
Locking CodeLock(SocketLock); // Single thread the code.
boost::asio::async_read(*pSocket, boost::asio::buffer(pDataBuf, ByteCount), boost::bind(&SSLSocket::HandleRead,
this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
// boost::asio::read(pSocket, boost::asio::buffer(reply_), boost::asio::transfer_exactly(ByteCount), Err);
}
else
{
Log.LogString("SSLSocket::HandleRead failed: " + error.message() + "\n", LogError);
Stop();
}
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::HandleRead: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
void SSLSocket::Stop()
{
// This method calls the shutdown method on the socket in order to stop reads or writes that might be going on. If this is not done, then an exception will be thrown
// when it comes time to delete this object.
ReqAlive = false;
SetEvent(hEvent);
IOService->stop();
}
所以,这里是关键点:
第一次连接到服务器时,会创建 SSLSocket 类的一个新实例。 io_service 对象是静态的,只创建一次。它被 SSLSocket 类的所有 6 个实例使用。
有 2 个线程用于与所有 6 个服务器之间的套接字通信有关的所有事情。一个线程用于处理从服务器接收到的消息。另一个线程用于向服务器发送消息。
此代码使用 SSL/TSL。如果您使用直接 TCP,则只需删除 SSLSocket::Connect 方法中的 3 行以及 ssl #include 行。
HandleRead 中使用的技术使用双读方法。第一次读取获取字节数(因为协议(protocol)使用前 4 个字节作为消息长度),第二次读取获取该消息中的总字节数。这可能不是处理从套接字读取数据的最有效甚至最理想的方式。但是,它是最容易理解的。如果您的协议(protocol)不同和/或消息大小大得多并且您有能力在收到整条消息之前开始处理消息,您可能会考虑使用不同的方法。
此代码使用 Boost 1.52.0 和 Visual Studio 2008 for Windows。
关于c++ - Boost asio - 多个客户端连接到不同的服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15434753/
我知道这个问题可能已经被问过,但我检查了所有这些,我认为我的情况有所不同(请友善)。所以我有两个数据集,第一个是测试数据集,第二个是我保存在数据框中的预测(预测值,这就是没有数据列的原因)。我想合并两
在 .loc 方法的帮助下,我根据同一数据框中另一列中的值来识别 Panda 数据框中某一列中的值。 下面给出了代码片段供您引用: var1 = output_df['Player'].loc[out
当我在 Windows 中使用 WinSCP 通过 Ubuntu 连接到 VMware 时,它提示: The server rejected SFTP connection, but it lis
我正在开发一个使用 xml web 服务的 android 应用程序。在 wi-fi 网络中连接时工作正常,但在 3G 网络中连接时失败(未找到 http 404)。 这不仅仅发生在设备中。为了进行测
我有一个XIB包含我的控件的文件,加载到 Interface Builder(Snow Leopard 上的 Xcode 4.0.2)中。 文件的所有者被设置为 someClassController
我在本地计算机上管理 MySQL 数据库,并通过运行以下程序通过 C 连接到它: #include #include #include int main(int argc, char** arg
我不知道为什么每次有人访问我网站上的页面时,都会打开一个与数据库的新连接。最终我到达了大约 300 并收到错误并且页面不再加载。我认为它应该工作的方式是,我将 maxIdle 设置为 30,这意味着
希望清理 NMEA GPS 中的 .txt 文件。我当前的代码如下。 deletes = ['$GPGGA', '$GPGSA', '$GPGSV', '$PSRF156', ] searchquer
我有一个 URL、一个用户名和一个密码。我想在 C# .Net WinForms 中建立 VPN 连接。 你能告诉我从哪里开始吗?任何第三方 API? 代码示例将受到高度赞赏... 最佳答案 您可以像
有没有更好的方法将字符串 vector 转换为字符 vector ,字符串之间的终止符为零。 因此,如果我有一个包含以下字符串的 vector "test","my","string",那么我想接收一
我正在编写一个库,它不断检查 android 设备的连接,并在设备连接、断开连接或互联网连接变慢时给出回调。 https://github.com/muddassir235/connection_ch
我的操作系统:Centos 7 + CLOUDLINUX 7.7当我尝试从服务器登录Mysql时 [root@server3 ~]# Mysql -u root -h localhost -P 330
我收到错误:Puma 发现此错误:无法打开到本地主机的 TCP 连接:9200(连接被拒绝 - 连接(2)用于“本地主机”端口 9200)(Faraday::ConnectionFailed)在我的
请给我一些解决以下错误的方法。 这是一个聊天应用....代码和错误如下:: conversations_controller.rb def create if Conversation.bet
我想将两个单元格中的数据连接到一个单元格中。我还想只组合那些具有相同 ID 的单元格。 任务 ID 名称 4355.2 参与者 4355.2 领袖 4462.1 在线 4462.1 快速 4597.1
我经常需要连接 TSQL 中的字段... 使用“+”运算符时 TSQL 强制您处理的两个问题是 Data Type Precedence和 NULL 值。 使用数据类型优先级,问题是转换错误。 1)
有没有在 iPad 或 iPhone 应用程序中使用 Facebook 连接。 这个想法是登录这个应用程序,然后能够看到我的哪些 facebook 用户也在使用该应用程序及其功能。 最佳答案 是的。
我在连接或打印字符串时遇到了一个奇怪的问题。我有一个 char * ,可以将其设置为字符串文字的几个值之一。 char *myStrLiteral = NULL; ... if(blah) myS
对于以下数据 - let $x := "Yahooooo !!!! Select one number - " let $y := 1 2 3 4 5 6 7 我想得到
我正在看 UDEMY for perl 的培训视频,但是视频不清晰,看起来有错误。 培训展示了如何使用以下示例连接 2 个字符串: #!usr/bin/perl print $str = "Hi";
我是一名优秀的程序员,十分优秀!