Sending struct over tcp socket in C++ - c++

I am trying to send struct over tcp socket. I am a newbie in socket programming, I did try the options suggested here already but those did not serve my purpose. Could someone pls help?
I have written Server.cpp and Client.cpp and both are compiling properly. However, when I am executing my Server to listen to the Client, I am not sure if the Server is able to recieve the structure from Client or not. Also, how can I read this structure once it is received?
Server.cpp
#include<iostream>
#include <cstring>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string>
#include<stdio.h>
using namespace std;
int main()
{
struct UE
{
string Net;
int imsi;
} ;
UE UE2;
//cout<<UE1.imsi<<"\n"<<UE1.Net<<"\n";
int sock, cli, receive;
sockaddr_in server, client;
unsigned int len;
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket:");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(10000);
//cout<<htons(10000);
server.sin_addr.s_addr = INADDR_ANY;
//cout<<INADDR_ANY;
memset(&(server.sin_zero), '\0', 8);
len = sizeof(struct sockaddr_in);
if((bind(sock, (struct sockaddr *)&server, len)) == -1)
{
perror("Bind:");
exit(-1);
}
if((listen(sock, 5)) == -1)
{
perror("Listen:");
exit(-1);
}
while(1)
{
cli = accept(sock,(struct sockaddr *)&client, &len);
if(cli == -1)
{
perror("Accept");
exit(-1);
}
receive = recv(sock, (void*)&UE2, sizeof(UE2), NULL);
cout<<UE2.imsi;
//cout<<UE2.imsi<<"\n"<<UE2.Net;
//int sent = send(cli, (const void*)&mesg, sizeof mesg, 0);
//cout<<"Sent"<<sent<<" bytes to client :<<inet_ntoa(client.sin_addr)";
close(cli);
}
}
Client.cpp
#include <arpa/inet.h>
#include<iostream>
#include <cstring>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string>
#include<stdio.h>
using namespace std;
int main(int argc, char *argv[])
{
struct UE
{
string Net;
int imsi;
} ;
UE UE1;
UE1.Net = "4G";
UE1.imsi = htons(8649);
int sock, receive;
struct sockaddr_in server;
char mesg[200];
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket:");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
//cout<<server.sin.port;
server.sin_addr.s_addr = inet_addr(argv[1]);
//cout<<server.sin_addr.s_addr;
memset(&(server.sin_zero), '\0', 8);
if(connect(sock, (struct sockaddr*)&server, sizeof(server)) == -1)
{
perror("Connect:");
exit(-1);
}
int count = 0;
while(count = 0)
{
send(sock, &UE1, sizeof(UE1), 0);
//receive = recv(sock, (void*)&mesg, sizeof mesg, NULL);
count++;
}
cout<<"Sent "<<UE1.imsi<<" and "<<UE1.Net<<" to Server \n";
close(sock);
}

There are at least 2 problems in your code:
You cannot send objects like std::string and anything that contains it this way (formally non-POD data), you need to marshall your data. There are plenty of libraries around (like google proto buffers) or you can write your own. This topic is too wide to cover it in the answer here.
You cannot expect that you receive data from TCP stream by the same chunk you sent it, you must write code that can handle receiving data by pieces (and send it that way as well).

You should never ever write a whole struct to a file or a socket.
Always write each field separately, and read them the same way.
When doing it this way you pay some memory overhead, but it's generally a good design for performance reasons because you don't want to do a write of each value to the socket.
When sending binary data you should always take care for the following things:
Different endianness
Different padding
Differences in the bye-sizes of intrinsic types
You need some functions like the following:
virtual MESSAGE_BUFFER * GetMessageAsBinaryPtr()
{
MESSAGE_BUFFER * binaryMsg = new MESSAGE_BUFFER;
UINT8 * ptrBuffer = &(*binaryMsg)[0];
ptrBuffer = this->serializeUInt16(ptrBuffer, this->m_majorVersion);
ptrBuffer = this->serializeUInt16(ptrBuffer, this->m_minorVersion);
ptrBuffer = this->serializeUInt32(ptrBuffer, (UINT32)this->m_messageType);
ptrBuffer = this->serializeUInt64(ptrBuffer, this->m_packetID);
ptrBuffer = this->serializeDouble(ptrBuffer, this->m_timestamp);
return binaryMsg;
}
virtual void CreateFromBinary(MESSAGE_BUFFER buffer)
{
UINT8 * ptrBuffer = &buffer[0];
ptrBuffer = this->deserializeUInt16FromBuffer(ptrBuffer, &this->m_majorVersion);
ptrBuffer = this->deserializeUInt16FromBuffer(ptrBuffer, &this->m_minorVersion);
UINT32 messageType = 0;
ptrBuffer = this->deserializeUInt32FromBuffer(ptrBuffer, &messageType);
this->SetMessageType((MessageTypes)messageType);
ptrBuffer = this->deserializeUInt64FromBuffer(ptrBuffer, &this->m_packetID);
ptrBuffer = this->deserializeDoubleFromBuffer(ptrBuffer, &this->m_timestamp);
}
inline UINT8 * serializeUInt16(UINT8 * buffer, UINT16 value)
{
buffer[1] = value;
buffer[0] = value >> 8;
return buffer + 2;
}
inline UINT8 * deserializeUInt16FromBuffer(UINT8 * buffer, UINT16 * pOutput)
{
*pOutput = (*pOutput << 8) + buffer[0];
*pOutput = (*pOutput << 8) + buffer[1];
return buffer + 2;
}
When you have such functions you can serialize and deserialize your structs to a buffer and then send this buffer over your socket.
A few points to note:
The struct to send is first serialized, field by field into a buffer
MESSAGE_BUFFER is of type UINT8[1024]
The serialization routine returns a pointer to the next free byte in the buffer, which we use to compute how many bytes it serialized to
Theres no protection against buffer overflows in my routines

There are few bugs in your code.
In server.cpp
sockaddr_in --> struct sockaddr_in
Once connection request is accepted by server using accept() call, it returns new file descriptor, with that new fd you should do read and write operation not with old one.
Replace below statement
receive = recv(sock, (void*)&UE2, sizeof(UE2), NULL); /** you are receiving with old fd called sock **/
with
receive = recv(cli, (void*)&UE2, sizeof(UE2), NULL);
client.cpp
using namespace std;
int main(int argc, char *argv[])
{
struct UE
{
string Net;
int imsi;
} ;
UE UE1;
UE1.Net = "4G";
UE1.imsi = htons(8649);
int sock, receive;
struct sockaddr_in server;
char mesg[200];
sock = socket(PF_INET, SOCK_STREAM, 0);
perror("Socket:");
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
memset(&(server.sin_zero), '\0', 8);
connect(sock, (struct sockaddr*)&server, sizeof(server));
perror("Connect:");
int count = 0;
send(sock, &UE1, sizeof(UE1), 0);
perror("send");
cout<<"Sent "<<UE1.imsi<<" and "<<UE1.Net<<" to Server \n";
close(sock);
}
server.cpp
using namespace std;
int main()
{
struct UE
{
string Net;
int imsi;
} ;
UE UE2;
int sock, cli, receive;
struct sockaddr_in server, client;
unsigned int len;
sock = socket(AF_INET, SOCK_STREAM, 0);
perror("Socket:");
server.sin_family = AF_INET;
server.sin_port = htons(10001);
server.sin_addr.s_addr = INADDR_ANY;
memset(&(server.sin_zero), '\0', 8);
len = sizeof(server);
bind(sock, (struct sockaddr *)&server, len);
perror("Bind:");
listen(sock, 1);
perror("Listen:");
cli = accept(sock,(struct sockaddr *)&client, &len);
perror("accept");
receive = recv(cli, ( void*)&UE2, sizeof(UE2), 0);
perror("recv");
cout << "rec = "<<receive<<endl;
cout<<UE2.imsi<<"\n";
close(sock);
perror("close");
}

Related

How to write to a socket file descriptor without using ``connect()``?

I'm trying to write through a socket using its descriptor. I have used bind() to bind the socket to the address I want. Whenever I'm using sendto() everything is OK. But whenever I'm using write() (or send()) I'll face Destination address required(errno 89).
What I'm trying to do is to write through the socket using iovec. In this case we don't have any alternative for writev() to get destination address. As I don't want to connect every single time, I was wondering whether I can do it without having to use connect() or accept() syscalls.
Here is the code I wrote:
int sock = 0;
struct sockaddr_in serv_addr;
char *hello = "chetori to";
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
int opt = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
string interface_name = "lo";
ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface_name.c_str());
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, reinterpret_cast<void*>(&ifr), sizeof(ifr)) < 0)
throw exception(); // Imaginary exception
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
string interface_address = "127.0.0.1";
if (inet_aton(interface_address.c_str(), &serv_addr.sin_addr) == 0)
throw exception(); // Imaginary exception
serv_addr.sin_port = htons(PORT);
if (bind(sock, reinterpret_cast<sockaddr*>(&serv_addr), sizeof(serv_addr)) < 0)
throw exception(); // Imaginary exception
char f[1024] = "Hello there";
char sec[1024] = "How are you";
char th[1024] = "I'm fine";
char fh[1024] = "Bye bye";
struct iovec bufs[] = {
{ .iov_base = f, .iov_len = sizeof(f) },
{ .iov_base = sec, .iov_len = sizeof(sec) },
{ .iov_base = th, .iov_len = sizeof(th) },
{ .iov_base = fh, .iov_len = sizeof(fh) },
};
int iovcnt = sizeof(bufs) / sizeof(struct iovec);
writev(sock, bufs, iovcnt);
Note that Interface name and IP address have no problem and are correct.

Raw Socket send TCP SYN-FIN-.. in c++

My teacher want us to do an exercise on raw socket in c ++ on Windows (for learning tcp communication).
I have got a problem with it. I saw a lot of documentation but I don't know how to solve it.
int raw()
{
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN sin,din;
WSAStartup(MAKEWORD(2, 2), &WSAData);
char datagram[MAX_PACKET_SIZE];
struct iphdr *iph = (struct iphdr *)datagram;
struct tcphdr *tcph = (struct tcphdr *)((UCHAR *)iph + sizeof(tcphdr));
char new_ip[sizeof "255.255.255.255"];
sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
cout << "failled init socket" << endl ;
else{
memset(datagram, 0, MAX_PACKET_SIZE); // Clear the data
setup_ip_header(iph);
setup_tcp_header(tcph);
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.s_addr = inet_addr("192.168.1.10"); //source ip
din.sin_family = AF_INET;
din.sin_port = htons(DEST_PORT);
din.sin_addr.s_addr = inet_addr(TARGET_SERV_IP); //ip serv to connect
tcph->port_dest = htons(DEST_PORT);
iph->ip_dest = din.sin_addr.s_addr;
iph->ip_source = sin.sin_addr.s_addr;
iph->ip_dest = inet_addr(TARGET_SERV_IP); //ip serv to connect
iph->ip_source = inet_addr("192.168.1.10"); //source ip
//iph->checksum = csum((unsigned short *)datagram, iph->tot_len >> 1);
iph->checksum = csum((unsigned short *)datagram, sizeof(struct iphdr));
int one = 1;
const int *val = &one;
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)val, sizeof(one)) < 0)
printf("failled set socket option IP_HDRINCL");
else{
if (sendto(sock, /* our socket */
datagram, /* the buffer containing headers and data */
ntohs( iph->tot_len), /* total length of our datagram */
0, /* routing flags, normally always 0 */
(struct sockaddr *) &sin, /* socket addr, just like in */
sizeof(sin)) < 0) /* a normal send() */
cout << stderr << "sendto() error!!!.\n " << WSAGetLastError() << endl;
else
cout << "packet send\n" << endl;
}
closesocket(sock);
}
}
My error occurs at the sendto(). it return 10022 error = WSAEINVAL
I saw that can be a new windows protection?
Have you any idea to fix my problem or bypass the protection (go deeper, driver, etc)
You don't set iph->tot_len in your code.
My recommendation for networking code using c++ would be to use std::string or std::vector:
std::vector<uint8_t> packet(MAX_PACKET_SIZE, 0);
...
packet.resize(real_size);
then use the address (&packet[0]) for your pointer manipulations.

C++ UDP recvfrom is acting strange, WSAGetLastError = 10014

My code is behaving very strange on Windows, but working on Linux...
This is my server.cpp:
#include <cstdio>
#include "packet.h"
#include "socket.h"
int main(int argc, char *argv[])
{
Socket s;
s.bindAt(1337);
for (int i = 0; i < 20; i++) {
Packet p;
int32_t a;
char *b;
int abc = s.receive();
printf("abc = %d\n", abc);
printf("error = %d\n", WSAGetLastError());
p.getInt(&a);
p.getString(&b);
printf("int = %d\nstring = %s\n", a, b);
delete[] b;
}
return 0;
}
and here is the socket.cpp:
Socket::Socket()
{
#ifdef _WIN32
WSADATA wsa;
if (sockNum == 0 && WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
throw 1;
#endif
sock = socket(AF_INET, SOCK_DGRAM, 0);
#ifdef _WIN32
if (sock == INVALID_SOCKET)
#else
if (sock == -1)
#endif
throw 2;
addrlen = 0;
sockNum++;
}
int Socket::bindAt(unsigned short port)
{
struct sockaddr_in sa = { 0 };
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
return bind(sock, (struct sockaddr *) &sa, sizeof(sa));
}
ssize_t Socket::receive()
{
ssize_t n;
#ifdef _WIN32
char msg[100];
n = recvfrom(sock,msg, sizeof(msg), 0,(SOCKADDR*) &addr, &addrlen);
#else
n = recvfrom(sock, p->buf, p->bufSize, 0,
(struct sockaddr *) &addr, &addrlen);
#endif
/*if (n < 0)
p->bufSize = 0;
else
p->bufSize = n;*/
return n;
}
and basically the header of it:
typedef SOCKET socket_t;
typedef int ssize_t;
class Socket
{
public:
socket_t sock;
socklen_t addrlen;
struct sockaddr_in addr;
Socket();
~Socket();
int connect(const char *ip, unsigned short port);
int bindAt(unsigned short port);
ssize_t send(Packet *p);
ssize_t receive();
};
If I change the last 2 parameters of the recvfrom, the (SOCKADDR*) &addr, and &addrlen to NULL it works, but what is wrong with these 2 parameters?
instead of this :
addrlen = 0;
do this:
addrlen = sizeof(sockaddr_in)
it should work, because you are identifying correctly the size of the output address buffer pointer.
From MSDN description of WSAEFAULT (10014):
The system detected an invalid pointer address in attempting to use a pointer argument of a call. This error occurs if an application passes an invalid pointer value, or if the length of the buffer is too small. For instance, if the length of an argument, which is a sockaddr structure, is smaller than the sizeof(sockaddr).
So if you supply an uninitialized value of addrlen, it may be too small, and result in this error.
If addr is NULL, it means you don't want the address filled in, so addrlen is ignored.

c++ tcp server (windows OS) - recv() delays when there is more then 1 connection to the server

When I'm trying to connect to the server with only 1 client, the recv() function on the server does not delay.
But when I'm starting the client console more then 1 time (something like 7 times), there is a delay of something like 2000ms after you send to the server packet with the function send() until the server will print the packet in is console.
Is there any solution without starting a thread for each client? (Windows limits the number of threads for each process).
The code is compiled with Visual Studio 2008, and this is the full server code:
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include <Windows.h>
#include <stdio.h>
struct sslv3
{
#define max_clients 1024
private:
int cClient;
public:
SOCKET fd;
int CurrentClient()
{
return cClient;
}
struct client
{
client()
{
Valid = false;
}
bool Valid;
DWORD ip;
WORD port;
char ipstr[33];
char portstr[33];
SOCKET fd;
void StrGen()
{
wsprintf(ipstr, "%d.%d.%d.%d", ip & 0xFF, (ip & 0xFF00)/0x100, (ip & 0xFF0000)/0x10000, (ip & 0xFF000000)/0x1000000);
wsprintf(portstr, "%d", port);
}
} clients[max_clients];
//
sslv3(bool server_client)
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
cClient = 0;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//
DWORD timeout = 1;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
}
int Bind(WORD port)
{
int ret = 0;
sockaddr_in local;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(port);
if((ret = bind(fd, (struct sockaddr *)&local, sizeof(local)))
!= SOCKET_ERROR)
listen(fd, SOMAXCONN);
return ret;
}
int Accept()
{
SOCKET clientfd;
sockaddr_in client;
int addrlen = sizeof(client);
clientfd = accept(fd, (struct sockaddr *)&client, &addrlen);
if(clientfd == -1)
return -1;
clients[cClient].ip = client.sin_addr.S_un.S_addr;
clients[cClient].port = client.sin_port;
clients[cClient].StrGen();
clients[cClient].fd = clientfd;
clients[cClient].Valid = true;
//
DWORD timeout = 1;
setsockopt(clients[cClient].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
cClient++;
if(cClient >= max_clients)
{
cClient = 0;
return max_clients - 1;
}
return cClient - 1;
}
int Connect(char ip[], WORD port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
return connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
}
int Send(SOCKET sfd, void* buffer, int length)
{
return send(sfd, (char*)buffer, length, 0);
}
int Read(SOCKET sfd, void* buffer, int length)
{
return recv(sfd, (char*)buffer, length, 0);
}
};
sslv3 cssl(true);
DWORD WINAPI ReadThread(void* args)
{
while(true)
{
for(int j = 0; j <= cssl.CurrentClient(); j++)
{
if(cssl.clients[j].Valid)
{
char rpack[1024];
for(int i = 0; i < sizeof(rpack); i++)
rpack[i] = 0;
if(cssl.Read(cssl.clients[j].fd, rpack, sizeof(rpack)) > 0){
printf("%s:%s says: %s\n", cssl.clients[j].ipstr, cssl.clients[j].portstr, rpack);
}
}
}
Sleep(1);
}
return TRUE;
}
int main()
{
cssl.Bind(1234);
CreateThread(0,0,ReadThread,0,0,0);
while(true)
{
Sleep(1);
int cid = cssl.Accept();
if(cid != -1){
printf("%s:%s connected!\n", cssl.clients[cid].ipstr, cssl.clients[cid].portstr);
}
}
return 0;
}
The following is a full client code:
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
struct sslv3
{
#define max_clients 1024
private:
int cClient;
public:
SOCKET fd;
int CurrentClient()
{
return cClient;
}
struct client
{
client()
{
Valid = false;
}
bool Valid;
DWORD ip;
WORD port;
char ipstr[33];
char portstr[33];
SOCKET fd;
void StrGen()
{
wsprintf(ipstr, "%d.%d.%d.%d", ip & 0xFF, (ip & 0xFF00)/0x100, (ip & 0xFF0000)/0x10000, (ip & 0xFF000000)/0x1000000);
wsprintf(portstr, "%d", port);
}
} clients[max_clients];
//
sslv3(bool server_client)
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
cClient = 0;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//
DWORD timeout = 1;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
}
int Bind(WORD port)
{
int ret = 0;
sockaddr_in local;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(port);
if((ret = bind(fd, (struct sockaddr *)&local, sizeof(local)))
!= SOCKET_ERROR)
listen(fd, SOMAXCONN);
return ret;
}
int Accept()
{
SOCKET clientfd;
sockaddr_in client;
int addrlen = sizeof(client);
clientfd = accept(fd, (struct sockaddr *)&client, &addrlen);
if(clientfd == -1)
return -1;
clients[cClient].ip = client.sin_addr.S_un.S_addr;
clients[cClient].port = client.sin_port;
clients[cClient].StrGen();
clients[cClient].fd = clientfd;
clients[cClient].Valid = true;
//
DWORD timeout = 1;
setsockopt(clients[cClient].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
cClient++;
if(cClient >= max_clients)
{
cClient = 0;
return max_clients - 1;
}
return cClient - 1;
}
int Connect(char ip[], WORD port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
return connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
}
int Send(SOCKET sfd, void* buffer, int length)
{
return send(sfd, (char*)buffer, length, 0);
}
int Read(SOCKET sfd, void* buffer, int length)
{
return recv(sfd, (char*)buffer, length, 0);
}
};
sslv3 cssl(false);
int main()
{
cssl.Connect("127.0.0.1", 1234);
while(true)
{
printf("say: ");
char buf[1024];
for(int i = 0; i < sizeof(buf); i++)
buf[i] = 0;
cin >> buf;
int len = strlen(buf);
cssl.Send(cssl.fd, buf, len);
}
return 0;
}
The server seems 'idle' for 2 seconds, because some clients are handled after 2 sleeps, 1 second each.
This is clearly not the right way to handle more than one client on a server. You may want to check on select() - reference.
A very good tutorial for socket programming is Beej's

Google protocol buffers doesn't work with UDP?

I know it could be silly but my message pack defined with Google protocol buffers is not happily working with UDP while perfectly with TCP.
When I send a regular string from serialized package(in which I only have some plain fields) from client to server through UDP, every thing's fine. But when I add a repeated field, the serialized string could only be received a part of the whole. The first field will be received completely, but all the rest will be lost.
The code is written in c++, Google protocol buffers 2.3.0, Linux.
Any help is welcomed.
Thanks.
My proto file is below:
message Package{
optional string virtualPath = 1;
optional int32 num = 2;//0=insert, 1=find, 2=remove.
optional string realFullPath = 3;
optional bool isDir = 4;
repeated string listItem = 5;
optional int32 openMode = 6;
optional int32 mode = 7;
optional int32 Operation = 8;
optional int32 replicaNo =9;
}
Server side:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include "zht_util.h"
int main(int argc, char *argv[]) {
struct sockaddr_in sad;
int port = 50000;
struct sockaddr_in cad;
int alen;
int serverSocket;
char clientSentence[1000];
char capitalizedSentence[1000];
char buff[1000];
int i, n;
serverSocket = socket(PF_INET, SOCK_DGRAM, 0); /* CREATE SOCKET */
if (serverSocket < 0) {
fprintf(stderr, "socket creation failed\n");
exit(1);
}
memset((char *) &sad, 0, sizeof(sad));
sad.sin_family = AF_INET;
sad.sin_addr.s_addr = INADDR_ANY;
sad.sin_port = htons((u_short) port);
if (bind(serverSocket, (struct sockaddr *) &sad, sizeof(sad)) < 0) {
fprintf(stderr, "bind failed\n");
exit(1);
}
while (1) {
clientSentence[0] = '\0';
alen = sizeof(struct sockaddr);
socklen_t len = (socklen_t) alen;
n = recvfrom(serverSocket, buff, sizeof(buff), 0,
(struct sockaddr *) &cad, &len);
strncat(clientSentence, buff, n);
printf("Server received :%s \n", clientSentence);
}
return 0;
}
Client side:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include "zht_util.h"
int main(int argc, char *argv[])
{
struct sockaddr_in sad;
int clientSocket;
struct hostent *ptrh;
char *host;
int port;
char Sentence[1000];
char modifiedSentence[1000];
char buff[1000];
int n;
host = "localhost";
port = 50000;
clientSocket = socket(PF_INET, SOCK_DGRAM, 0);
if (clientSocket < 0) {
fprintf(stderr, "socket creation failed\n");
exit(1);
}
memset((char *)&sad,0,sizeof(sad));
sad.sin_family = AF_INET;
sad.sin_port = htons((u_short)port);
ptrh = gethostbyname(host);
if ( ((char *)ptrh) == NULL ) {
fprintf(stderr,"invalid host: %s\n", host);
exit(1);
}
memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
HostEntity destination;
destination.host = "localhost";
destination.port = 50000;
int current_sock = -1;
Package package;
package.set_virtualpath(randomString(25));
package.add_listitem("item--1");
package.add_listitem("item--2");
package.add_listitem("item--3");
package.add_listitem("item--4");
package.add_listitem("item--5");
package.set_realfullpath("Some-Real-longer-longer-and-longer-Paths");
cout << "package size: " << package.ByteSize() << endl;
char array[package.ByteSize()];
package.SerializeToArray(array, package.ByteSize());
strcpy(Sentence, array);
n=sendto(clientSocket, Sentence, strlen(Sentence)+1,0 ,
(struct sockaddr *) &sad, sizeof(struct sockaddr));
printf(" Client sent %d bytes to the server\n", n);
close(clientSocket);
return 0;
}
For the problem that Jon mentioned, I tried this too, still doesn't work.
string Sentence = package.SerializeAsString();
n=sendto(clientSocket, Sentence.c_str(), (Sentence.size())+1,0 ,(struct sockaddr *) &sad, sizeof(struct sockaddr));
I suspect this is the problem:
strcpy(Sentence, array);
You're using strcpy - that's going to stop as soon as it hits a 0 byte, because it's treating this somewhat arbitrary binary data as a string. I suspect you should be using memcpy instead.
Likewise, don't use strlen later on. Avoid all functions which treat the data as text.
(In general I'd be wary of using protocol buffers with UDP unless you've got a good reason to believe each message will fit in a single packet, but that's a separate matter.)