Reputation: 9
I'm totally new to networking and just started to use Cap'n Proto too.
This is some sample program from here:
void writeAddressBook(int fd) {
::capnp::MallocMessageBuilder message;
AddressBook::Builder addressBook = message.initRoot<AddressBook>();
::capnp::List<Person>::Builder people = addressBook.initPeople(2);
Person::Builder alice = people[0];
alice.setId(123);
alice.setName("Alice");
alice.setEmail("[email protected]");
// Type shown for explanation purposes; normally you'd use auto.
::capnp::List<Person::PhoneNumber>::Builder alicePhones =
alice.initPhones(1);
alicePhones[0].setNumber("555-1212");
alicePhones[0].setType(Person::PhoneNumber::Type::MOBILE);
alice.getEmployment().setSchool("MIT");
Person::Builder bob = people[1];
bob.setId(456);
bob.setName("Bob");
bob.setEmail("[email protected]");
auto bobPhones = bob.initPhones(2);
bobPhones[0].setNumber("555-4567");
bobPhones[0].setType(Person::PhoneNumber::Type::HOME);
bobPhones[1].setNumber("555-7654");
bobPhones[1].setType(Person::PhoneNumber::Type::WORK);
bob.getEmployment().setUnemployed();
writePackedMessageToFd(fd, message);
}
The last line uses writePackedMessageToFd()
which takes fd
as a file descriptor and message
created by MallocMessageBuilder
.
I work on Windows with Visual Studio 2017.
I would like to send message
to a remote server which will answer with a similar Cap'nP object.
The question is how can I send it and receive the answer?
I tried to initialize and create a socket in the following way:
//Initialize WinSock
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0) {
cerr << "Can't start WinSock, Error #" << wsResult << endl;
return;
}
else {
cout << "Socket initialized!" << endl;
}
//Create socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
cerr << "Can't create socket, Error #" << WSAGetLastError() << endl;
WSACleanup();
return;
}
else {
cout << "Socket created!" << endl;
}
If everything went fine socket()
return a file descriptor.
So I just used
writePackedMessageToFd(sock, message)
, but didn't work.
By the way I don't understand this concept since the socket doesn't "know" which IP and port I want to use. I should specify them when I use the connect()
function.
I tried to skip the writePackedMessageToFd()
function. Connected to the server with connect()
and just used Windows' send()
function to send the message
. Something like this:
string ipAddress = "127.0.0.1"; //IP Address of server
int port = 58661; //Listening port of server
//Initialize WinSock
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0) {
cerr << "Can't start WinSock, Error #" << wsResult << endl;
return;
}
else {
cout << "Socket initialized!" << endl;
}
//Create socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
cerr << "Can't create socket, Error #" << WSAGetLastError() << endl;
WSACleanup();
return;
}
else {
cout << "Socket created!" << endl;
}
//Fill in a hint structure
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
//Connect to server
int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (connResult == SOCKET_ERROR) {
cerr << "Can't connect to server, Error #" << WSAGetLastError() << endl;
closesocket(sock);
WSACleanup();
return;
}
else {
cout << "Connected to " << ipAddress << " on port " << port << endl;
}
//Send and receive data
char buf[4096];
//string mess = "Hello";
//Send message
//int sendResult = send(sock, mess.c_str(), mess.size() + 1, 0);
int sendResult = send(sock, (const char*)&message, sizeof(message) + 1, 0);
//Wait for response
ZeroMemory(buf, 4096);
int bytesReceived = recv(sock, buf, 4096, 0);
if (bytesReceived > 0) {
cout << "SERVER>" << string(buf, 0, bytesReceived) << endl;
}
//Close down everything
closesocket(sock);
WSACleanup();
cout << "Connection closed!" << endl;
This one sended something but it was definitely wrong because the server didn't respond.
In brief: I would like to send and receive Cap'n Proto packed messages over TCP connection to a specified IP:port.
How could I accomplish this? I really need some help.
I would really really appreciate Your help! Thanks in advance!
Upvotes: 0
Views: 2283
Reputation: 45246
On Windows, socket()
does not return a file descriptor. It returns a Windows SOCKET
, which is actually a HANDLE
cast to an integer. On Windows, "file descriptors" are implemented as a compatibility layer in the C runtime library; they are not directly supported by the OS.
You can use kj::HandleInputStream
and kj::HandleOutputStream
to perform I/O on sockets on Windows.
kj::HandleOutputStream out((HANDLE)sock);
capnp::writeMessage(out, message);
And:
kj::HandleInputStream in((HANDLE)sock);
capnp::InputStreamMessageReader message(in);
Upvotes: 1