I'm studying ZeroMQ with myself.
I tested PUB as a server(bind), SUB as a client(connect) and worked fine. Opposite (PUB as a client(connect), SUB as a server(bind)) also works fine.
When I connect a another SUB socket as client something goes wrong without any exception or errors.
here's my example code.
#include <zmq.hpp>
#include <string>
#include <iostream>
#include <unistd.h>
#include <thread>
class ZMQSock
{
public:
ZMQSock(const char* addr)
{
if (addr != NULL)
{
mctx = new zmq::context_t(1);
mszAddr = new char[strlen(addr) + 1];
snprintf(mszAddr, strlen(addr) + 1, "%s", addr);
}
}
virtual ~ZMQSock()
{
if (msock != nullptr)
delete msock;
if (mctx != nullptr)
delete mctx;
if (mszAddr != nullptr)
delete [] mszAddr;
}
int zbind()
{
if (msock != nullptr)
msock->bind(mszAddr);
else return -1;
return 0;
}
int zconnect()
{
if (msock != nullptr)
msock->connect(mszAddr);
else return -1;
return 0;
}
void start()
{
if (mbthread != false)
return ;
mbthread = true;
mhthread = std::thread(std::bind(&ZMQSock::run, this));
}
virtual void stop()
{
if (mbthread == false)
return ;
mbthread = false;
if (mhthread.joinable())
mhthread.join();
}
virtual void run() = 0;
protected:
char* mszAddr{nullptr};
zmq::context_t* mctx{nullptr};
zmq::socket_t* msock{nullptr};
bool mbthread{false};
std::thread mhthread;
};
class ZPublisher : public ZMQSock
{
public:
ZPublisher(const char* addr) : ZMQSock(addr)
{
if (msock == nullptr)
{
msock = new zmq::socket_t(*mctx, ZMQ_PUB);
}
}
virtual ~ZPublisher()
{
}
bool zsend(const char* data, const unsigned int length, bool sendmore=false)
{
zmq::message_t msg(length);
memcpy(msg.data(), data, length);
if (sendmore)
return msock->send(msg, ZMQ_SNDMORE);
return msock->send(msg);
}
void run()
{
if (mszAddr == nullptr)
return ;
if (strlen(mszAddr) < 6)
return ;
const char* fdelim = "1";
const char* first = "it sends to first. two can not recv this sentence!\0";
const char* sdelim = "2";
const char* second = "it sends to second. one can not recv this sentence!\0";
while (mbthread)
{
zsend(fdelim, 1, true);
zsend(first, strlen(first));
zsend(sdelim, 1, true);
zsend(second, strlen(second));
usleep(1000 * 1000);
}
}
};
class ZSubscriber : public ZMQSock
{
public:
ZSubscriber(const char* addr) : ZMQSock(addr)
{
if (msock == nullptr)
{
msock = new zmq::socket_t(*mctx, ZMQ_SUB);
}
}
virtual ~ZSubscriber()
{
}
void setScriberDelim(const char* delim, const int length)
{
msock->setsockopt(ZMQ_SUBSCRIBE, delim, length);
mdelim = std::string(delim, length);
}
std::string zrecv()
{
zmq::message_t msg;
msock->recv(&msg);
return std::string(static_cast<char*>(msg.data()), msg.size());
}
void run()
{
if (mszAddr == nullptr)
return ;
if (strlen(mszAddr) < 6)
return ;
while (mbthread)
{
std::cout << "MY DELIM IS [" << mdelim << "] - MSG : ";
std::cout << zrecv() << std::endl;
usleep(1000 * 1000);
}
}
private:
std::string mdelim;
};
int main ()
{
ZPublisher pub("tcp://localhost:5252");
ZSubscriber sub1("tcp://localhost:5252");
ZSubscriber sub2("tcp://*:5252");
pub.zconnect();
sub1.zconnect();
sub2.zbind();
sub1.setScriberDelim("1", 1);
sub2.setScriberDelim("2", 1);
pub.start();
std::cout << "PUB Server has been started.." << std::endl;
usleep(1000 * 1000);
sub1.start();
std::cout << "SUB1 Start." << std::endl;
sub2.start();
std::cout << "SUB2 Start." << std::endl;
int i = 0;
std::cout << "< Press any key to exit program. >" << std::endl;
std::cin >> i;
std::cout << "SUB1 STOP START" << std::endl;
sub1.stop();
std::cout << "SUB2 STOP START" << std::endl;
sub2.stop();
std::cout << "PUB STOP START" << std::endl;
pub.stop();
std::cout << "ALL DONE" << std::endl;
return 0;
}
What causes this? or Am I using PUB/SUB illegally?
You are connecting a SUB socket to a SUB socket, that is an invalid connection. In your case the PUB should bind and the SUBs should connect.
Related
On Windows I am able to enumerate removable drives using FindFirstVolume, FindNextVolume, GetVolumePathNamesForVolumeName and the GetDriveType functions. How can I achieve this on Linux and macOS?
On macOS you need to work with IOKit: https://developer.apple.com/documentation/iokit
It can looks like the following code:
#include <cstdlib>
#include <iostream>
#include <mach/mach_port.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOTypes.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>
std::string get_descriptor_idx(IOUSBDeviceInterface **dev, UInt8 idx);
int main(int argc, char *argv[]) {
/*
* Get the IO registry
*/
auto entry = IORegistryGetRootEntry(kIOMasterPortDefault);
if (entry == 0)
return EXIT_FAILURE;
io_iterator_t iter{};
auto kret = IORegistryEntryCreateIterator(entry, kIOUSBPlane, kIORegistryIterateRecursively, &iter);
if (kret != KERN_SUCCESS || iter == 0)
return EXIT_FAILURE;
io_service_t service {};
std::cout << std::endl;
while ((service = IOIteratorNext(iter))) {
IOCFPlugInInterface **plug = nullptr;
IOUSBDeviceInterface **dev = nullptr;
io_string_t path;
SInt32 score = 0;
IOReturn ioret;
kret = IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plug, &score);
IOObjectRelease(service);
if (kret != KERN_SUCCESS || plug == nullptr) {
continue;
}
/*
* USB
*/
ioret = (*plug)->QueryInterface(plug, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
static_cast<LPVOID *>((void *) &dev));
(*plug)->Release(plug);
if (ioret != kIOReturnSuccess || dev == nullptr) {
continue;
}
if (IORegistryEntryGetPath(service, kIOServicePlane, path) != KERN_SUCCESS) {
(*dev)->Release(dev);
continue;
}
std::cout << "USB Path: " << path << std::endl;
UInt8 si;
UInt16 u16v;
if ((*dev)->GetDeviceVendor(dev, &u16v) == kIOReturnSuccess)
std::cout << "VID: "<< u16v << std::endl;
if ((*dev)->GetDeviceProduct(dev, &u16v) == kIOReturnSuccess)
std::cout << "PID: "<< u16v << std::endl;
if ((*dev)->USBGetManufacturerStringIndex(dev, &si) == kIOReturnSuccess) {
std::cout << "Manufacturer: " << get_descriptor_idx(dev, si) << std::endl;
}
if ((*dev)->USBGetProductStringIndex(dev, &si) == kIOReturnSuccess) {
std::cout << "Product: " << get_descriptor_idx(dev, si) << std::endl;
}
(*dev)->Release(dev);
std::cout << std::endl;
}
IOObjectRelease(iter);
return 0;
}
/* a quick version */
std::string get_descriptor_idx(IOUSBDeviceInterface **dev, UInt8 idx)
{
IOUSBDevRequest request;
IOReturn ioret;
char buffer[4086] = { 0 };
CFStringRef cfstr;
CFIndex len;
request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
request.bRequest = kUSBRqGetDescriptor;
request.wValue = (kUSBStringDesc << 8) | idx;
request.wIndex = 0x409;
request.wLength = sizeof(buffer);
request.pData = buffer;
ioret = (*dev)->DeviceRequest(dev, &request);
if (ioret != kIOReturnSuccess)
return "n/a";
if (request.wLenDone <= 2)
return "n/a";
cfstr = CFStringCreateWithBytes(nullptr, (const UInt8 *)buffer+2, request.wLenDone-2, kCFStringEncodingUTF16LE, 0);
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr), kCFStringEncodingUTF8) + 1;
if (len < 0) {
CFRelease(cfstr);
return "n/a";
}
std::string str; str.resize(len);
CFStringGetCString(cfstr, str.data(), len, kCFStringEncodingUTF8);
CFRelease(cfstr);
return str;
}
In my case the result ıs:
USB Path: IOService:/AppleARMPE/arm-io/xxxx/USB2.1 Hub#01100000
VID: 1507
PID: 1552
Manufacturer: GenesysLogic
Product: USB2.1 USB
I am beginning to learn about sockets in wxWidgets, and run on Windows 10 (latest version), CodeBlocks 20.03 with mingw2 (gnu 11.2), and wxWidgets 3.15.
The socket sample compiles and run OK.
Because I will be sending many wxStrings (up to 7000 in one session) from the client to the server, I added a for-loop in the client.cpp OnTest2 function (see below).
Where the single transfer of the original socket sample runs OK every time, the adapted client.cpp OnTest2 function always logs Input-Available events at various locations.
For some reason "Input-Available" is logged on all sends.
The Server receives everything, so I am not worried that much about the future content.
Still, these Input-Available Log messages should not happen, I think.
I read somewhere that calling wxThread::Yield() prior to calling WaitForRead() would help, but it did not.
Is something wrong in my "simple" approach of adding a for-loop?
I hope someone can help me understand why these Input-Available log message appear,
and help me find a solution.
Edit:
I have reduced the wxWidgets socket examples to the smallest of my 'beginners' abilities.
minclient.cpp
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
# include "wx/wx.h"
#endif
#include "wx/socket.h"
#include "wx/sstream.h"
class MyApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
};
class MyFrame : public wxFrame
{
public:
MyFrame();
~MyFrame();
void OnQuit(wxCommandEvent& event);
void OnOpenConnection(wxCommandEvent& event);
void OnCloseConnection(wxCommandEvent& event);
void OpenConnection(wxSockAddress::Family family);
void OnSocketEvent(wxSocketEvent& event);
void OnTest(wxCommandEvent& event);
private:
wxSocketClient *m_sock;
wxMenu *m_menuFile;
wxMenu *m_menuSocket;
wxMenuBar *m_menuBar;
wxDECLARE_EVENT_TABLE();
};
enum
{
CLIENT_QUIT = wxID_EXIT,
CLIENT_ABOUT = wxID_ABOUT,
CLIENT_OPEN = 100,
CLIENT_TEST,
CLIENT_CLOSE,
SOCKET_ID
};
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(CLIENT_QUIT, MyFrame::OnQuit)
EVT_MENU(CLIENT_OPEN, MyFrame::OnOpenConnection)
EVT_MENU(CLIENT_TEST, MyFrame::OnTest)
EVT_MENU(CLIENT_CLOSE, MyFrame::OnCloseConnection)
EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
if ( !wxApp::OnInit() )
return false;
MyFrame *frame = new MyFrame();
frame->Show(true);
return true;
}
MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, wxID_ANY,
_("wxSocket demo: Client"),
wxDefaultPosition, wxSize(300, 200))
{
m_menuFile = new wxMenu();
m_menuFile->AppendSeparator();
m_menuFile->Append(CLIENT_QUIT, _("E&xit\tAlt-X"), _("Quit client"));
m_menuSocket = new wxMenu();
m_menuSocket->Append(CLIENT_OPEN, _("&Open session\tCtrl-O"), _("Connect to server"));
m_menuSocket->AppendSeparator();
m_menuSocket->Append(CLIENT_TEST, _("Test &2\tCtrl-F2"), _("Test ReadMsg and WriteMsg"));
m_menuSocket->AppendSeparator();
m_menuSocket->Append(CLIENT_CLOSE, _("&Close session\tCtrl-C"), _("Close connection"));
m_menuBar = new wxMenuBar();
m_menuBar->Append(m_menuFile, _("&File"));
m_menuBar->Append(m_menuSocket, _("&TCP"));
SetMenuBar(m_menuBar);
m_sock = new wxSocketClient();
m_sock->SetEventHandler(*this, SOCKET_ID);
m_sock->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
m_sock->Notify(true);
}
MyFrame::~MyFrame()
{
delete m_sock;
}
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close(true);
}
void MyFrame::OnOpenConnection(wxCommandEvent& WXUNUSED(event))
{
OpenConnection(wxSockAddress::IPV4);
}
void MyFrame::OpenConnection(wxSockAddress::Family family)
{
wxIPaddress * addr;
wxIPV4address addr4;
addr = &addr4;
m_menuSocket->Enable(CLIENT_OPEN, false);
m_menuSocket->Enable(CLIENT_CLOSE, false);
wxString hostname = "localhost";
addr->Hostname(hostname);
addr->Service(3000);
m_sock->Connect(*addr, false);
}
void MyFrame::OnCloseConnection(wxCommandEvent& WXUNUSED(event))
{
m_sock->Close();
}
void MyFrame::OnSocketEvent(wxSocketEvent& event)
{
switch ( event.GetSocketEvent() )
{
case wxSOCKET_INPUT:
std::cout << "Input available on the socket.\n";
break;
case wxSOCKET_LOST:
std::cout << "Socket connection was unexpectedly lost.\n";
break;
case wxSOCKET_CONNECTION:
std::cout << "... socket is now connected.\n";
break;
default:
std::cout << "Unknown socket event!\n";
break;
}
}
void MyFrame::OnTest(wxCommandEvent& WXUNUSED(event))
{
for(int f = 0; f < 2; f++)
{
unsigned char c = 0xCE;
m_sock->Write(&c, 1);
m_sock->SetFlags(wxSOCKET_WAITALL);
wxString s = "This is my string to send";
const wxScopedCharBuffer msg1(s.utf8_str());
size_t len = wxStrlen(msg1) + 1;
wxCharBuffer msg2(wxStrlen(msg1));
m_sock->WriteMsg(msg1, len);
if(m_sock->Error())
{ std::cout << " Write failed !\n"; }
m_sock->WaitForRead(2);
if (m_sock->IsData())
{
m_sock->ReadMsg(msg2.data(), len);
if(m_sock->Error())
{ std::cout << " Read failed !\n"; }
else
{
if (memcmp(msg1, msg2, len) != 0)
{ std::cout << "Test failed !\n"; }
else
{ std::cout << "Returned msg: \"" << msg2 << "\"" << std::endl; }
}
}
else
{ std::cout << "Timeout ! Test failed.\n"; }
}
}
minserver.cpp
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
# include "wx/wx.h"
#endif
#include "wx/socket.h"
typedef wxIPV4address IPaddress;
class MyApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
};
class MyFrame : public wxFrame
{
public:
MyFrame();
~MyFrame();
void OnQuit(wxCommandEvent& event);
void OnServerEvent(wxSocketEvent& event);
void OnSocketEvent(wxSocketEvent& event);
void Test(wxSocketBase *sock);
private:
wxSocketServer *m_server;
wxMenu *m_menuFile;
wxMenuBar *m_menuBar;
int m_numClients;
wxDECLARE_EVENT_TABLE();
};
enum
{
SERVER_QUIT = wxID_EXIT,
SERVER_ID = 100,
SOCKET_ID
};
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(SERVER_QUIT, MyFrame::OnQuit)
EVT_SOCKET(SERVER_ID, MyFrame::OnServerEvent)
EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
if ( !wxApp::OnInit() )
return false;
MyFrame *frame = new MyFrame();
frame->Show(true);
return true;
}
MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, wxID_ANY,
_("wxSocket demo: Server"),
wxDefaultPosition, wxSize(300, 200))
{
m_menuFile = new wxMenu();
m_menuFile->Append(SERVER_QUIT, _("E&xit\tAlt-X"), _("Quit server"));
m_menuBar = new wxMenuBar();
m_menuBar->Append(m_menuFile, _("&File"));
SetMenuBar(m_menuBar);
IPaddress addr;
addr.Service(3000);
m_server = new wxSocketServer(addr);
if (! m_server->IsOk())
{
std::cout << "Could not listen at the specified port !\n";
return;
}
IPaddress addrReal;
if ( !m_server->GetLocal(addrReal) )
{ std::cout << "ERROR: couldn't get the address we bound to.\n"; }
else
{ std::cout << "Server listening at " << addrReal.IPAddress() << ": " << addrReal.Service() << std::endl; }
m_server->SetEventHandler(*this, SERVER_ID);
m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
m_server->Notify(true);
m_numClients = 0;
}
MyFrame::~MyFrame()
{
delete m_server;
}
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close(true);
}
void MyFrame::OnServerEvent(wxSocketEvent& event)
{
wxString s = "OnServerEvent: ";
wxSocketBase *sock;
switch(event.GetSocketEvent())
{
case wxSOCKET_CONNECTION:
s.Append("wxSOCKET_CONNECTION");
break;
default:
s.Append("Unexpected event !");
break;
}
std::cout << s << std::endl;
sock = m_server->Accept(false);
if (sock)
{
IPaddress addr;
if ( !sock->GetPeer(addr) )
{ std::cout << "New connection from unknown client accepted.\n"; }
else
{ std::cout << "New client connection from " << addr.IPAddress() << ":" << addr.Service() << " accepted\n"; }
}
else
{
std::cout << "Error: couldn't accept a new connection\n";
return;
}
sock->SetEventHandler(*this, SOCKET_ID);
sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
sock->Notify(true);
m_numClients++;
}
void MyFrame::OnSocketEvent(wxSocketEvent& event)
{
wxString s = "OnSocketEvent: ";
wxSocketBase *sock = event.GetSocket();
switch(event.GetSocketEvent())
{
case wxSOCKET_INPUT:
s.Append(_("wxSOCKET_INPUT"));
break;
case wxSOCKET_LOST:
s.Append(_("wxSOCKET_LOST"));
break;
default:
s.Append(_("Unexpected event !"));
break;
}
std::cout << s << std::endl;
switch(event.GetSocketEvent())
{
case wxSOCKET_INPUT:
{
sock->SetNotify(wxSOCKET_LOST_FLAG);
unsigned char c;
sock->Read(&c, 1);
switch (c)
{
case 0xCE:
Test(sock);
break;
default:
std::cout << "Unknown test id received from client\n";
}
sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG);
break;
}
case wxSOCKET_LOST:
{
m_numClients--;
std::cout << "Deleting socket.\n";
sock->Destroy();
break;
}
default: ;
}
}
void MyFrame::Test(wxSocketBase *sock)
{
char buf[4096];
wxUint32 len = sock->ReadMsg(buf, sizeof(buf)).LastCount();
if ( !len )
{
std::cout << "Failed to read message.\n";
return;
}
std::cout << "Received: \"" << wxString::FromUTF8(buf, len) << "\" , Returning it\n";
sock->WriteMsg(buf, len);
}
The below message on the client happens at every 'test'. (Also when the for loop is removed.)
Input available on the socket
I searched for socket libraries, and found only 8 sort of current ones.
(Boos.ASIO, beej, bestofcpp, netlib, and others)
They were either to complicated for me to start with, or had python dependency.
I appreciate suggestions for easy to learn alternative libraries.
I am trying to communicate with forked child process using message queue from boost interprocess library. When child process calls receive it causes exception with message
boost::interprocess_exception::library_error
I am using GCC 6.3 on Debian 9 x64.
#include <iostream>
#include <unistd.h>
#include <boost/interprocess/ipc/message_queue.hpp>
#include <memory>
int main(int argc, char* argv[])
{
using namespace boost::interprocess;
const char* name = "foo-552b8ae9-6037-4b77-aa0d-d4dc9dad790b";
const int max_num_msg = 100;
const int max_msg_size = 32;
bool is_child = false;
message_queue::remove(name);
auto mq = std::make_unique<message_queue>(create_only, name, max_num_msg, max_msg_size);
auto child_pid = fork();
if (child_pid == -1)
{
std::cout << "fork failed" << std::endl;
return -1;
}
else if (child_pid == 0)
{
is_child = true;
}
if (is_child)
{
// does child needs to reopen it?
mq.reset( new message_queue(open_only, name) );
}
int send_num = 0;
while(true)
{
unsigned int priority = 0;
if (is_child)
{
message_queue::size_type bytes = 0;
try
{
int num;
// Always throws. What is wrong ???????
mq->receive(&num, sizeof(num), bytes, priority);
std::cout << num << std::endl;
}
catch(const std::exception& e)
{
std::cout << "Receive caused execption " << e.what() << std::endl;
}
sleep(1);
}
else
{
mq->send(&send_num, sizeof(send_num), priority);
send_num++;
sleep(5);
}
}
return 0;
}
Also, in child process is it required to reopen the message queue created by the parent process? I tried it both ways and neither worked. I am getting the same exception on receive.
The problem is that your receive buffer is smaller than max_msg_size. Assuming 4-byte integers, this should work:
int num[8];
mq.receive(num, sizeof(num), bytes, priority);
std::cout << *num << std::endl;
Also, I see no reason to play fast and loose with the actual queue instance. Just create it per process:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <iostream>
#include <memory>
#include <unistd.h>
int main() {
namespace bip = boost::interprocess;
const char *name = "foo-552b8ae9-6037-4b77-aa0d-d4dc9dad790b";
{
const int max_num_msg = 100;
const int max_msg_size = 32;
bip::message_queue::remove(name);
bip::message_queue mq(bip::create_only, name, max_num_msg, max_msg_size);
}
auto child_pid = fork();
if (child_pid == -1) {
std::cout << "fork failed" << std::endl;
return -1;
}
bip::message_queue mq(bip::open_only, name);
if (bool const is_child = (child_pid == 0)) {
while (true) {
unsigned int priority = 0;
bip::message_queue::size_type bytes = 0;
try {
int num[8];
mq.receive(num, sizeof(num), bytes, priority);
std::cout << *num << std::endl;
} catch (const bip::interprocess_exception &e) {
std::cout << "Receive caused execption " << boost::diagnostic_information(e, true) << std::endl;
}
sleep(1);
}
} else {
// parent
int send_num = 0;
while (true) {
unsigned int priority = 0;
mq.send(&send_num, sizeof(send_num), priority);
send_num++;
sleep(5);
}
}
}
When i do the initialisation of the TCPServer inside of main it works, when i try to start it with the startServer() function it is not working, i mean i can not establish a connection with putty.
What am i doing wrong here?
Thanks for any help.
class EchoConnection : public TCPServerConnection {
public:
EchoConnection(const StreamSocket& s)
: TCPServerConnection(s) {}
void reply(char buffer[])
{
bzero(buffer, 256);
std::string myWord = "myWord\n\r";
strcpy(buffer, myWord.c_str());
}
void run() {
StreamSocket& ss = socket();
try {
char buffer[256];
int n = ss.receiveBytes(buffer, sizeof(buffer));
while (n > 0) {
reply(buffer);
ss.sendBytes(buffer, sizeof(buffer));
n = ss.receiveBytes(buffer, sizeof(buffer));
}
}
catch (Poco::Exception& exc)
{ std::cerr << "EchoConnection: " << exc.displayText() << std::endl; }
}
};
void startServer()
{
Poco::Net::TCPServer srv(new Poco::Net::TCPServerConnectionFactoryImpl<EchoConnection>, 8089);
srv.start();
SocketAddress sa("localhost", srv.socket().address().port());
StreamSocket ss(sa);
std::string data("hello, world");
ss.sendBytes(data.data(), (int)data.size());
char buffer[256] = { 0 };
int n = ss.receiveBytes(buffer, sizeof(buffer));
std::cout << std::string(buffer, n) << std::endl;
}
int main(int argc, char** argv) {
Poco::Net::TCPServer srv(new Poco::Net::TCPServerConnectionFactoryImpl<EchoConnection>, 8089);
srv.start();
SocketAddress sa("localhost", srv.socket().address().port());
StreamSocket ss(sa);
std::string data("hello, world");
ss.sendBytes(data.data(), (int)data.size());
char buffer[256] = { 0 };
int n = ss.receiveBytes(buffer, sizeof(buffer));
std::cout << std::string(buffer, n) << std::endl;
// startServer(8089);
ModuleData modData;
modData.ModuleNumber = 1;
modData.ModuleTypeId = 1;
string test = modData.serialize();
ifstream dataFile;
dataFile.open("ModuleData.dat");
if (dataFile.is_open())
{
string line;
while (getline(dataFile, line))
{
cout << line << std::endl;
}
dataFile.close();
}
while (1)
{
}
srv.stop();
}
At the end of startServer function srv object is deleted. TCPServer uses own thread but it finishes working in destructor of TCPServer.
Look at implementation of ~TCPServer
TCPServer::~TCPServer() {
try {
stop();
_pDispatcher->release();
...
}
and see stop method implementation
void TCPServer::stop() {
if (!_stopped)
{
_stopped = true; // !!
_thread.join(); // waiting for thread
_pDispatcher->stop();
}
}
the body of thread function is in run method
void TCPServer::run()
{
while (!_stopped) // this flag was set by stop method
{
... // body of thread function
}
}
stop method sets _stopped on true, and for this reason thread finishes working.
I already succeeded when trying to connect a client to a server. But the server was using the loopback ip address. How is it possible to make a server using SDLNet so that i can access it from any computer that is connected to any network?
The problem is the code because I don't find any place where I can define another IP address for the server...
Here is the code for the server:
#include "Link\SDL\include\SDL.h"
#include "Link\SDL\include\SDL_net.h"
#include <iostream>
#include <vector>
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDLNet_Init();
int curid=2;
int playernum = 0;
char data[1400];
bool running=true;
SDL_Event event;
IPaddress ip;
SDLNet_ResolveHost(&ip,NULL,1234);
SDLNet_SocketSet sockets=SDLNet_AllocSocketSet(30); //max player
std::vector<TCPsocket> socketsvector;
TCPsocket server=SDLNet_TCP_Open(&ip);
while(running)
{
while(SDL_PollEvent(&event))
{
if(event.type==SDL_QUIT || event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_ESCAPE)
{
running=false;
break;
}
}
TCPsocket tmpsocket=SDLNet_TCP_Accept(server);
if(tmpsocket)
{
if(playernum<30)
{
SDLNet_TCP_AddSocket(sockets,tmpsocket);
socketsvector.push_back(tmpsocket);
sprintf(data,"0 %d \n",curid);
curid++;
playernum++;
std::cout << "new connection. ID: " << curid << std::endl;
}
else
{
sprintf(data,"3 \n"); //server is full
}
SDLNet_TCP_Send(tmpsocket,data,strlen(data)+1);
}
while(SDLNet_CheckSockets(sockets,0) > 0)
{
for(int i=0;i<socketsvector.size();i++)
{
if(SDLNet_SocketReady(socketsvector[i])==1)
{
SDLNet_TCP_Recv(socketsvector[i],data,1400);
int num=data[0]-'0';
int j=1;
while(data[j]>='0' && data[j]<='9')
{
num*=10;
num+=data[j]-'0';
j++;
}
if(num==1)
{
for(int k=0;k<socketsvector.size();k++)
{
if(k==i)
continue;
SDLNet_TCP_Send(socketsvector[k],data,strlen(data)+1);
}
}else if(num==2)
{
for(int k=0;k<socketsvector.size();k++)
{
if(k==i)
continue;
SDLNet_TCP_Send(socketsvector[k],data,strlen(data)+1);
}
SDLNet_TCP_DelSocket(sockets,socketsvector[i]);
SDLNet_TCP_Close(socketsvector[i]);
socketsvector.erase(socketsvector.begin()+i);
playernum--;
std::cout << "connection closed..." << std::endl;
std::cout << playernum << " players in server" << std::endl;
}
}
}
}
//SDL_Delay(30);
}
SDLNet_TCP_Close(server);
SDLNet_FreeSocketSet(sockets);
SDLNet_Quit();
SDL_Quit();
return 0;
}
Ok, and here is the code for the client...
class network{
private:
SDLNet_SocketSet sockets;
TCPsocket connection;
char data[1400];
public:
network(const char* ip);
~network();
void send(Player* p);
void receive(std::vector<Enemy*>& enemies, Player* p); //std::vector<unsigned int>& f,std::vector<enemy*>& enemies,std::vector<weapon*> weapons,player* p
void closeConnection();
};
network::network(const char* ipaddress)
{
SDLNet_Init();
IPaddress ip;
if(SDLNet_ResolveHost(&ip,ipaddress,1234)==-1)
std::cout << "error while resolving the host (bad ip?)" << std::endl;
connection=SDLNet_TCP_Open(&ip);
sockets=SDLNet_AllocSocketSet(1);
if(sockets==NULL)
std::cout << "error while connecting (bad ip?)" << std::endl;
SDLNet_TCP_AddSocket(sockets,connection);
}
void network::closeConnection()
{
SDLNet_TCP_Send(connection,"2 \n",4); //close with the server
}
network::~network()
{
SDLNet_TCP_Close(connection);
SDLNet_FreeSocketSet(sockets);
SDLNet_Quit();
}
void network::send(Player* p)
{
vector3d vec=p->cam.getVector();
//1 curframe position rotation lookdirection health curweaponnum
sprintf(data,"1 %d %f %f %f %f %f %f \n",p->id, p->cam.getLocation().x,p->cam.getLocation().y,p->cam.getLocation().z,vec.x,vec.y,vec.z);
int size=0;
int len=strlen(data)+1;
//SDLNet_TCP_Send(connection,data,len);
while(size<len)
{
size+=SDLNet_TCP_Send(connection,data+size,len-size);
}
}
void network::receive(std::vector<Enemy*>& enemies, Player* p) //std::vector<unsigned int>& f,std::vector<enemy*>& enemies,std::vector<weapon*> weapons,player* p
{
SDLNet_CheckSockets(sockets,10);
if(SDLNet_SocketReady(connection))
{
int tmp,num;
int offset=0;
do
{
offset=SDLNet_TCP_Recv(connection,(char*)data+(offset),1400);
if(offset<=0)
return;
}while(data[strlen(data)-1]!='\n');
sscanf(data,"%d %d",&num,&tmp);
//cout << num << " " << tmp << endl;
cout << data << endl;
int i=0;
if(num == 0)
{
p->setId(tmp);
}
else if(num==1)
{
bool NewEnemy = true;
for(i=0;i<enemies.size();i++)
{
if(enemies[i]->id == tmp)
{
int nothing;
sscanf(data,"1 %d %f %f %f %f %f %f \n",¬hing, &(enemies[i]->position.x),&(enemies[i]->position.y),&(enemies[i]->position.z),&(enemies[i]->rotation.x),&(enemies[i]->rotation.y),&(enemies[i]->rotation.z));
NewEnemy = false;
break;
}
}
if(NewEnemy == true && tmp != 0)
{
std::cout << "pusing new enemy" << std::endl;
enemies.push_back(new Enemy(tmp));
}
}
else if(num == 2)
{
for(int k = 0; k < enemies.size(); k++)
{
if(enemies[k]->id == tmp)
{
enemies.erase(enemies.begin() + k);
}
}
}
else if(num == 3)
{
std::cout << "Could not connect. Server is full." << std::endl;
}
}
}
If you can see, I type the IP address for the client when the program starts. But the only value that works is the loopback address.