Protocol Buffer over socket in C++ - c++

I am trying to explore Protocol Buffer (PB) in Linux platform and my coding language is C++. I found examples in the protocol buffer online docs but nothing specific to socket send and receive (Or I have missed it completely :) ). So I decided to add the message Length before the actual message and send it across socket. I would appreciate if anyone can suggest a better solution than what I am planning to do and also is there anything ready made in PB for creating such packets.
But I still end up with a problem at server side where I have to decode the packet. Say if the client sends a packet of 10 byte in which first 4 byte is the length of the packet; But it is impossible to know the length before decoding the packet. So even if i read the first 4 byte how do i deduce the the value with half read packet using Protocol Buffer.

At last I could get it working . I am posting the code here so that one can review and comment on it as well as if some one wants to implement it in c++, this piece of code can help. Its a shabby code my intention was to get Protobuf working in length prefixed manner. I have taken the code of client server from some site which I don't remember and I have modified it to accommodate protobuf. Here the server first peeks into the socket and gets the length of the total packet and then actual socket read is done to read the entire packet. There can be zillion ways to do it but for quick solution I did it in this manner. But I need to find a better way to avoid 2 recv per packets, but in my condition all the messages are of different size, so this is the only way I guess.
Proto file
message log_packet {
required fixed64 log_time =1;
required fixed32 log_micro_sec =2;
required fixed32 sequence_no =3;
required fixed32 shm_app_id =4;
required string packet_id =5;
required string log_level=6;
required string log_msg=7;
}
Protocol buffer Client Code
#include <unistd.h>
#include "message.pb.h"
#include <iostream>
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
using namespace google::protobuf::io;
using namespace std;
int main(int argv, char** argc){
/* Coded output stram */
log_packet payload ;
payload.set_log_time(10);
payload.set_log_micro_sec(10);
payload.set_sequence_no(1);
payload.set_shm_app_id(101);
payload.set_packet_id("TST");
payload.set_log_level("DEBUG");
payload.set_log_msg("What shall we say then");
cout<<"size after serilizing is "<<payload.ByteSize()<<endl;
int siz = payload.ByteSize()+4;
char *pkt = new char [siz];
google::protobuf::io::ArrayOutputStream aos(pkt,siz);
CodedOutputStream *coded_output = new CodedOutputStream(&aos);
coded_output->WriteVarint32(payload.ByteSize());
payload.SerializeToCodedStream(coded_output);
int host_port= 1101;
char* host_name="127.0.0.1";
struct sockaddr_in my_addr;
char buffer[1024];
int bytecount;
int buffer_len=0;
int hsock;
int * p_int;
int err;
hsock = socket(AF_INET, SOCK_STREAM, 0);
if(hsock == -1){
printf("Error initializing socket %d\n",errno);
goto FINISH;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
(setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
printf("Error setting options %d\n",errno);
free(p_int);
goto FINISH;
}
free(p_int);
my_addr.sin_family = AF_INET ;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = inet_addr(host_name);
if( connect( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
if((err = errno) != EINPROGRESS){
fprintf(stderr, "Error connecting socket %d\n", errno);
goto FINISH;
}
}
for (int i =0;i<10000;i++){
for (int j = 0 ;j<10;j++) {
if( (bytecount=send(hsock, (void *) pkt,siz,0))== -1 ) {
fprintf(stderr, "Error sending data %d\n", errno);
goto FINISH;
}
printf("Sent bytes %d\n", bytecount);
usleep(1);
}
}
delete pkt;
FINISH:
close(hsock);
}
Protocol buffer Server Code
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <netinet/in.h>
#include <resolv.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include "message.pb.h"
#include <iostream>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
using namespace std;
using namespace google::protobuf::io;
void* SocketHandler(void*);
int main(int argv, char** argc){
int host_port= 1101;
struct sockaddr_in my_addr;
int hsock;
int * p_int ;
int err;
socklen_t addr_size = 0;
int* csock;
sockaddr_in sadr;
pthread_t thread_id=0;
hsock = socket(AF_INET, SOCK_STREAM, 0);
if(hsock == -1){
printf("Error initializing socket %d\n", errno);
goto FINISH;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
(setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
printf("Error setting options %d\n", errno);
free(p_int);
goto FINISH;
}
free(p_int);
my_addr.sin_family = AF_INET ;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = INADDR_ANY ;
if( bind( hsock, (sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
fprintf(stderr,"Error binding to socket, make sure nothing else is listening on this port %d\n",errno);
goto FINISH;
}
if(listen( hsock, 10) == -1 ){
fprintf(stderr, "Error listening %d\n",errno);
goto FINISH;
}
//Now lets do the server stuff
addr_size = sizeof(sockaddr_in);
while(true){
printf("waiting for a connection\n");
csock = (int*)malloc(sizeof(int));
if((*csock = accept( hsock, (sockaddr*)&sadr, &addr_size))!= -1){
printf("---------------------\nReceived connection from %s\n",inet_ntoa(sadr.sin_addr));
pthread_create(&thread_id,0,&SocketHandler, (void*)csock );
pthread_detach(thread_id);
}
else{
fprintf(stderr, "Error accepting %d\n", errno);
}
}
FINISH:
;//oops
}
google::protobuf::uint32 readHdr(char *buf)
{
google::protobuf::uint32 size;
google::protobuf::io::ArrayInputStream ais(buf,4);
CodedInputStream coded_input(&ais);
coded_input.ReadVarint32(&size);//Decode the HDR and get the size
cout<<"size of payload is "<<size<<endl;
return size;
}
void readBody(int csock,google::protobuf::uint32 siz)
{
int bytecount;
log_packet payload;
char buffer [siz+4];//size of the payload and hdr
//Read the entire buffer including the hdr
if((bytecount = recv(csock, (void *)buffer, 4+siz, MSG_WAITALL))== -1){
fprintf(stderr, "Error receiving data %d\n", errno);
}
cout<<"Second read byte count is "<<bytecount<<endl;
//Assign ArrayInputStream with enough memory
google::protobuf::io::ArrayInputStream ais(buffer,siz+4);
CodedInputStream coded_input(&ais);
//Read an unsigned integer with Varint encoding, truncating to 32 bits.
coded_input.ReadVarint32(&siz);
//After the message's length is read, PushLimit() is used to prevent the CodedInputStream
//from reading beyond that length.Limits are used when parsing length-delimited
//embedded messages
google::protobuf::io::CodedInputStream::Limit msgLimit = coded_input.PushLimit(siz);
//De-Serialize
payload.ParseFromCodedStream(&coded_input);
//Once the embedded message has been parsed, PopLimit() is called to undo the limit
coded_input.PopLimit(msgLimit);
//Print the message
cout<<"Message is "<<payload.DebugString();
}
void* SocketHandler(void* lp){
int *csock = (int*)lp;
char buffer[4];
int bytecount=0;
string output,pl;
log_packet logp;
memset(buffer, '\0', 4);
while (1) {
//Peek into the socket and get the packet size
if((bytecount = recv(*csock,
buffer,
4, MSG_PEEK))== -1){
fprintf(stderr, "Error receiving data %d\n", errno);
}else if (bytecount == 0)
break;
cout<<"First read byte count is "<<bytecount<<endl;
readBody(*csock,readHdr(buffer));
}
FINISH:
free(csock);
return 0;
}

Unfortunately, protobuf does not provide a way for "packaging" (delimiting) your messages:
If you want to write multiple messages to a single file or stream, it
is up to you to keep track of where one message ends and the next
begins. The Protocol Buffer wire format is not self-delimiting, so
protocol buffer parsers cannot determine where a message ends on their
own. The easiest way to solve this problem is to write the size of
each message before you write the message itself.
(from their documentation)
So, they basically recommend the same solution you arrived at.

Related

linux socket lose data when a delay is added before read

I am learning linux socket programming, I expect that server can read data, even I add a delay but it just drops the buffer data, and receive the recent data, that is why, Thanks. The code has been presented.
By the way, Could you show a common practice to deal with this kind of situation?
Server side C/C++ program to demonstrate Socket programming
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
const char hello[] = "Hello from server";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t *)&addrlen)) < 0)
{
perror("accept");
exit(EXIT_FAILURE);
}
for (int i = 0;; i++)
{
sleep(5);
valread = read(new_socket, buffer, 1024);
printf("%s\n", buffer);
}
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");
return 0;
}
Client side C/C++ program to demonstrate Socket programming
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
const char data[] = "Hello from client";
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
for (int i = 0;; i++)
{
sleep(1);
std::string hello = std::string(data) + std::to_string(i);
if (send(sock, hello.c_str(), hello.length() + 1, 0) != hello.length() + 1)
{
printf("error send %d \n", i);
}
printf("Hello message sent %d\n", i);
}
valread = read(sock, buffer, 1024);
printf("%s\n", buffer);
return 0;
}
The problem is, that the messages get concatenated in the socket. The socket represents a byte stream. Your sender puts bytes into the stream every second. On the first iteration, it writes "Hello from client0\0" (19 bytes) to the stream.
After one second, it writes "Hello from client1\0", and then "Hello from client2\0", "Hello from client3\0" and "Hello from client4\0", Now, after 5 Seconds, 5*19 = 95 bytes are written to the byte stream.
Now, the receiver calls valread = read(new_socket, buffer, 1024);. Guess what, it reads all 95 bytes (because you specified 1024 as buffer size) and sets valread to 95.
Then you call printf("%s\n", buffer);, which only prints the first 18 bytes of buffer, because there is a '\0' as 19th byte, which terminates '%s' format. Allthough 95 bytes are received, 76 bytes are missing in the output of your program.
If you use '\n' instead of '\0' as message separator and use write(1, buffer, valread) instead of printf("%s\n") on the receiving side, you will see all your data.
std::string hello = std::string(data) + std::to_string(i) + "\n";
if (send(sock, hello.c_str(), hello.length(), 0) != hello.length()) ...
Conclusion:
Stream sockets realize byte sreams, the do not preserve message boundaries.
If message bounaries must be preserved, you need to use a protocol on top of the stream to mark your message boundaries. The proptocol could be as simple as using '\n' as a message seaparator, as long as '\n' is not part of your message payload (e.g. when unsign a simple text protocol).
You block the server for 5 seconds and it cannot receive some messages from the client.
for (int i = 0;; i++)
{
sleep(5);
valread = read(new_socket, buffer, 1024);
printf("%s\n", buffer);
}
How can a client check if the server is receiving a message? I think this was discussed in Linux socket: How to make send() wait for recv()
P.S. It looks like there is a synchronizing piece of code, but you pulled it out of the loop.
Server:
}
send(new_socket, hello, strlen(hello), 0);
Client:
}
valread = read(sock, buffer, 1024);

C++ socket keeps receiving the same data

I am using this code to receive data from a sensor through sockets. The problem is that I keep receiving the same output for every iteration of the for loop. However I receive a different number for every time I run the code but again, the same number keeps repeating. The sensor should send different every time data but thats not the case here.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "port.h"
#define BUFSIZE 2048
int
main(int argc, char **argv)
{
struct sockaddr_in myaddr; /* our address */
struct sockaddr_in remaddr; /* remote address */
socklen_t addrlen = sizeof(remaddr); /* length of addresses */
int recvlen; /* # bytes received */
int fd; /* our socket */
int msgcnt = 0; /* count # of messages we received */
unsigned char buf[BUFSIZE]; /* receive buffer */
/* create a UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("cannot create socket\n");
return 0;
}
/* bind the socket to any valid IP address and a specific port */
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(SERVICE_PORT);
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror("bind failed");
return 0;
}
/* now loop, receiving data and printing what we received */
printf("waiting on port %d\n", SERVICE_PORT);
printf("%s \n \n", "We recieve 10 packets just to confirm the communication");
recvlen = recvfrom(fd, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
if (recvlen > 0) {
buf[recvlen] = 0;
printf("received message: \"%u\" (%d bytes)\n", buf, recvlen);
}
else
printf("uh oh - something went wrong!\n");
sprintf(buf, "ack %d", msgcnt++);
printf("sending response \"%u\"\n", buf);
if (sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&remaddr, addrlen) < 0)
perror("sendto");
int temp = recvlen;
for (;;) {
recvlen = recvfrom(fd, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
if (recvlen > 0) {
buf[recvlen] = 0;
printf("received message: \"%u\" (%d bytes)\n", buf, recvlen);
}
}
}
Edit:
Here is the output when i ran the code two seperate times:
trial run and
trial run 2
I believe the problem isn't with your networking code but rather with your printf() calls:
printf("received message: \"%u\" (%d bytes)\n", buf, recvlen);
You are specifying %u to print out the contents of buf, but buf is a char array (not an unsigned integer), so you probably want to be using %s instead.

WSAGetLastError 10038 in a C++ client

I create a C++ client that connect to a C++ server.
It connect and send correctly data to a server.
I create a separate thread to receive data from the server , and here is the problem that I can't figure it out.
I get this error:
WSAGetLastError 10038
I find that this error because the descriptor is not a socket.
The server send method work correcty, I test it with a telnet client.
This is my client code:
#include <winsock2.h>
#include <windows.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <conio.h>
#include<iostream>
using namespace std;
int hsock;
void *SocketHandler(void*);
int main(int argv, char** argc){
//The port and address you want to connect to
int host_port= 2000;//1101;
char* host_name="10.188.126.198";
pthread_t recept;
//Initialize socket support WINDOWS ONLY!
unsigned short wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 || ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 )) {
fprintf(stderr, "Could not find useable sock dll %d\n",WSAGetLastError());
return 0;
}
//Initialize sockets and set any options
int * p_int ;
hsock = socket(AF_INET, SOCK_STREAM, 0);
if(hsock == -1){
printf("Error initializing socket %d\n",WSAGetLastError());
return 0;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
(setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
printf("Error setting options %d\n", WSAGetLastError());
free(p_int);
return 0;
}
free(p_int);
//Connect to the server
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET ;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = inet_addr(host_name);
int *csock ;
csock = (int*)malloc(sizeof(int));
if( (*csock =connect( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr))) == SOCKET_ERROR ){
fprintf(stderr, "Error connecting socket %d\n", WSAGetLastError());
return 0;
}
cout<<"Client connect to :"<< htons(host_port)<<endl;
//Create thread to receive data from the server
// the problem is here as I think
pthread_create(&recept,NULL,SocketHandler,(void *)csock);
/// Send data to the server
char buffer[1024];
int buffer_len = 1024;
int bytecount;
int c;
while(true){
memset(buffer, '\0', buffer_len);
for(char* p=buffer ; (c=getch())!=13 ; p++){
printf("%c", c);
*p = c;
}
if( (bytecount=send(hsock, buffer, strlen(buffer),0))==SOCKET_ERROR){
fprintf(stderr, "Error sending data %d\n", WSAGetLastError());
return 0;
}
printf("Sent bytes %d\n", bytecount);
}
closesocket(hsock);
return 0;
}
void *SocketHandler(void* lp){
int *csock= (int*)lp;
cout<<"Start Listening Thread"<<endl;
char buffer[1024];
int buffer_len = 1024;
int bytecount;
memset(buffer, 0, buffer_len);
while(1){
memset(buffer, 0, buffer_len);
if((bytecount = recv(*csock, buffer, buffer_len, 0))==SOCKET_ERROR){
fprintf(stderr, "Error receiving data %d\n", WSAGetLastError());
break;
}
printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
}
free(csock);
return 0;
}
Function 'connect' returns result, not socket handle (https://msdn.microsoft.com/en-us/library/windows/desktop/ms737625%28v=vs.85%29.aspx). Change it to:
...
if (connect(hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == SOCKET_ERROR) {
fprintf(stderr, "Error connecting socket %d\n", WSAGetLastError());
return 0;
}
*csock = hsock;
...
The parameter that you send to the thread is the csock...
int *csock ;
csock = (int*)malloc(sizeof(int));
...
pthread_create(&recept,NULL,SocketHandler,(void *)csock);
and then you use the csock as a the socket (in the thread)...
int *csock= (int*)lp;
...
if((bytecount = recv(*csock, buffer, buffer_len, 0))==SOCKET_ERROR) {
I think that you need to use the hsock as your socket and not the *csock...
BTW:
In windows you should call it a SOCKET and not int...
Hope it helps...

Performing sequential send and receive operation in TCP socket programming

I am trying to implement Socket where client send sentence to server and server replies back two integer valeus pcount and ncount. I can receive both this but first recv operation receives both values and also appends some other data to buffer.
Client.cpp
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <netinet/in.h>
#include <resolv.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
char *foo(char* buf)
{
char buffer[1024];
char *a='\0';
char *c=buf;
strcpy(buffer,buf);
int host_port= 1102;
char* host_name="127.0.0.1";
struct sockaddr_in my_addr;
//char buffer[1024];
int bytecount;
int buffer_len=0;
int hsock;
int * p_int;
int err;
hsock = socket(AF_INET, SOCK_STREAM, 0);
if(hsock == -1){
printf("Error initializing socket %d\n",errno);
goto FINISH;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
(setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
printf("Error setting options %d\n",errno);
free(p_int);
goto FINISH;
}
free(p_int);
my_addr.sin_family = AF_INET ;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = inet_addr(host_name);
if( connect( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
if((err = errno) != EINPROGRESS){
fprintf(stderr, "Error connecting socket %d\n", errno);
goto FINISH;
}
}
//Now lets do the client related stuff
buffer_len = 1024;
memset(buf, '\0', buffer_len);
buf[strlen(buf)-1]='\0';
if( (bytecount=send(hsock, buffer, strlen(buffer),0))== -1){
fprintf(stderr, "Error sending data %d\n", errno);
go
to FINISH;
}
printf("Sent bytes %d\n", bytecount);
//-------
// may Needs to empty content of buffer here but dont know how to do. Tried with fflush, free(buffer) but does not work
//Two recv function which ideally recv pcount and ncount subsequently
if((bytecount = recv(hsock, buffer, buffer_len, 0))== -1){
fprintf(stderr, "Error receiving data %d\n", errno);
goto FINISH;
}
printf("Recieved bytes %d\nReceived string \"%s \n", bytecount, buffer);
//Needs to empty content of buffer here but dont know how to do. Tried with fflush, free(buffer) but does not work
if((bytecount = recv(hsock, buffer, buffer_len, 0))== -1){
fprintf(stderr, "Error receiving data %d\n", errno);
goto FINISH;
}
printf("Recieved bytes %d\nReceived string \"%s \n", bytecount, buffer);
close(hsock);
FINISH:
;
return buffer;
}
And server.cpp :
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <netinet/in.h>
#include <resolv.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
//#include <errno.h>
#include <stdio.h>
#include <netinet/in.h>
#include <resolv.h>
#include <sys/socket.h>
#include <unistd.h>
//#include <sstream.h>
#include <pthread.h>
#include "serverFunction.cpp"
#include "serverFunction2.cpp"
#include <iostream>
#include <sstream>
#include <cstdio>
using namespace std;
void *SocketHandler(void *);
int main(int argv, char **argc)
{
int host_port = 1102;
char buf[20];
int k;
struct sockaddr_in my_addr;
int hsock;
int *p_int;
int err;
socklen_t addr_size = 0;
int *csock;
sockaddr_in sadr;
pthread_t thread_id = 0;
hsock = socket(AF_INET, SOCK_STREAM, 0);
if (hsock == -1) {
printf("Error initializing socket %dn", errno);
goto FINISH;
}
p_int = (int *) malloc(sizeof(int));
*p_int = 1;
if ((setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char *) p_int, sizeof(int)) == -1) || (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char *) p_int, sizeof(int)) == -1)) {
printf("Error setting options %dn", errno);
free(p_int);
goto FINISH;
}
free(p_int);
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(hsock, (sockaddr *) & my_addr, sizeof(my_addr)) == -1) {
fprintf(stderr, "Error binding to socket, make sure nothing else is listening on this port %dn", errno);
goto FINISH;
}
if (listen(hsock, 10) == -1) {
fprintf(stderr, "Error listening %dn", errno);
goto FINISH;
}
//Now lets do the server stuff
addr_size = sizeof(sockaddr_in);
while (true) {
printf("waiting for a connectionn\n");
csock = (int *) malloc(sizeof(int));
if ((*csock = accept(hsock, (sockaddr *) & sadr, &addr_size)) != -1) {
printf("---------------------nReceived connection from %s\n", inet_ntoa(sadr.sin_addr));
pthread_create(&thread_id, 0, &SocketHandler, (void *) csock);
pthread_detach(thread_id);
} else {
fprintf(stderr, "Error accepting %dn", errno);
}
}
FINISH:
;
}
void *SocketHandler(void *lp)
{
int result=0;
//std::stringstream ss;
int *csock = (int *) lp;
char buf[20];
int k;
// char *target="my name is khan";
char *str;
char *str2;
int pcount = 0, ncount = 0;
char buffer[1024];
int buffer_len = 1024;
int bytecount;
int i = 0,t=0,q=0;
int j = 0;
char *ch[50] = { 0 }; /* stores references to 50 words. */
char *ch2[50] = { 0 };
char *word = strtok(buffer, " ");
char *word2 = strtok(buffer, " ");
char *portstring1=(char *)malloc(sizeof(buffer));
char *portstring2=(char *)malloc(sizeof(buffer));
memset(buffer, 0, buffer_len);
if ((bytecount = recv(*csock, buffer, buffer_len, 0)) == -1) {
fprintf(stderr, "Error receiving data %d \n", errno);
goto FINISH;
}
printf("Received bytes %d \n Received string %s \n ", bytecount, buffer);
/* stores references to 50 words. */
word = strtok(buffer, " ");
while ((NULL != word) && (50 > i)) {
ch[i] = strdup(word);
//printf("%s n", ch[i]);
str = BoyerMoore_positive(ch[i], strlen(ch[i]) - 1);
str2= BoyerMoore_negative(ch[i], strlen(ch[i]) - 1);
if (str == NULL)
t++;
else {
printf("%s \n", ch[i]);
// puts("true");
pcount += 1;
printf("Positive count is: %d \n",pcount);
}
if(str2== NULL)
q++;
else {
printf("%s \n", ch[i]);
// puts("true");
ncount += 1;
printf("Nagative count is: %d \n",ncount);
}
i++;
word = strtok(NULL, " ");
}
//I want to send pcount and ncount values to client
**sprintf(portstring1, "%d", pcount);
if ((bytecount = send(*csock, portstring1, 1, 0)) == -1) {
fprintf(stderr, "Error sending data %d\n", errno);
goto FINISH;
}
sprintf(portstring2, "%d", ncount);
if ((bytecount = send(*csock, portstring2, strlen(portstring2), 0)) == -1) {
fprintf(stderr, "Error sending data %d\n", errno);
goto FINISH;
}**
FINISH:
free(csock);
return 0;
}
I receive output like this:
Enter sentence to send to the server (press enter)
critic worst nice
Sent bytes 18
Recieved bytes 2
Received string 12itic worst nice //Here there should be only 1 2. Why 'itic ..' gets appended. And why 1 and 2 both does not get printed one after another
You forgot to design and implement a protocol. Network communication doesn't work by magic. If you have a notion of an application-level message, you have to write code to send and receive application-level messages. You haven't done this, so of course it won't happen.
Also:
printf("Received bytes %d \n Received string %s \n ", bytecount, buffer);
The %s format specifier is only for C-style strings. It's not suitable for arbitrary data. How would it know how many bytes to print?
The recv function does not add a nul character to terminate the received string. You have to add it yourself, like this:
if((bytecount = recv(hsock, buffer, buffer_len-1, 0))== -1){
fprintf(stderr, "Error receiving data %d\n", errno);
goto FINISH;
}
buffer[bytecount]=0;
Notice the -1 in buffer len, to make sure there's room for the nul character.
#Joni and David- Thanks for your support!
Problem solved:
at sender:
int ar[2];
if ((bytecount = send(*csock, (char *)ar, 2 *sizeof(int), 0)) == -1) { // Here we cant send lenth-1. It consider exact
fprintf(stderr, "Error sending data %d\n", errno);
goto FINISH;
}
at receiver side:
if((bytecount = recv(hsock, ar, 2 * sizeof(int), 0))== -1){
fprintf(stderr, "Error receiving data %d\n", errno);
goto FINISH;
}
for(k=0;k<2;k++)
{
printf("count is :%d",ar[k]);
}
just took and array, Now I can send any receive any numbers of values! It's so easy!

C++ CreateThread does not show result

i'm trying make asynchronous server listener with C++ i'm new in c++ but i must do this project , i'm web developer (PHP) but PHP can't make async connections + he is very poor language for big amount of connections... i can write simple listener without asynchronous but now i have problem with "CreateThread"... for example if client has been connected console gives me result about this + sniffer can fix it... after 10 sec client must send me again same packet with different data. my console does not gives me result about that packet but sniffer can see that packet... please if anyone can see my problem explain me ... (sorry for my bad english :D )
#include <winsock2.h>
#include <windows.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
DWORD WINAPI SocketHandler(void*);
int main(int argv, char** argc){
//The port you want the server to listen on
int host_port = 7878;
//Initialize socket support WINDOWS ONLY!
unsigned short wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 || ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 )) {
fprintf(stderr, "Could not find useable sock dll %d\n",WSAGetLastError());
}
//Initialize sockets and set any options
int hsock;
int * p_int ;
hsock = socket(AF_INET, SOCK_STREAM, 0);
if(hsock == -1){
printf("Error initializing socket %d\n",WSAGetLastError());
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
(setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
printf("Error setting options %d\n", WSAGetLastError());
free(p_int);
}
free(p_int);
//Bind and listen
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET ;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = INADDR_ANY ;
if( bind( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
fprintf(stderr,"Error binding to socket, make sure nothing else is listening on this port %d\n",WSAGetLastError());
}
if(listen( hsock, 10) == -1 ){
fprintf(stderr, "Error listening %d\n",WSAGetLastError());
}
//Now lets to the server stuff
int* csock;
sockaddr_in sadr;
int addr_size = sizeof(SOCKADDR);
while(true){
printf("waiting for a connection\n");
csock = (int*)malloc(sizeof(int));
if((*csock = accept( hsock, (SOCKADDR*)&sadr, &addr_size))!= INVALID_SOCKET ){
printf("Received connection from %s",inet_ntoa(sadr.sin_addr));
CreateThread(0,0,&SocketHandler, (void*)csock , 0,0);
}
else{
fprintf(stderr, "Error accepting %d\n",WSAGetLastError());
}
}
}
DWORD WINAPI SocketHandler(void* lp){
int *csock = (int*)lp;
char buffer[1024];
int buffer_len = 1024;
int bytecount;
memset(buffer, 0, buffer_len);
if((bytecount = recv(*csock, buffer, buffer_len, 0))==SOCKET_ERROR){
fprintf(stderr, "Error receiving data %d\n", WSAGetLastError());
}
printf("Received bytes %d\n Received string \"%s\"\n", bytecount, buffer);
char buff[1] = {0x11};
if((bytecount = send(*csock, buff, 1, 0))==SOCKET_ERROR){
fprintf(stderr, "Error sending data %d\n", WSAGetLastError());
}
printf("Sent bytes: %d. Send Message: %s\n ", bytecount,buff);
free(csock);
}
I suspect the issue not be the creating a thread, but in the passing of the data. It is probably simpler to just pass the socket to the thread. Additionally, at the end of the function you correctly free the memory, but you did not close the socket. I have made changes and verified that it functions correctly. The changes I made are comments with //*
#include <winsock2.h>
#include <windows.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
DWORD WINAPI SocketHandler(void*);
//*** Changed to work with my version of
//*** Visual Studio
int _tmain(int argc, _TCHAR* argv[]){
//The port you want the server to listen on
int host_port = 7878;
//Initialize socket support WINDOWS ONLY!
unsigned short wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 || ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 )) {
fprintf(stderr, "Could not find useable sock dll %d\n",WSAGetLastError());
}
//Initialize sockets and set any options
//*** Changed to be SOCKET instead of int
SOCKET hsock;
int * p_int ;
hsock = socket(AF_INET, SOCK_STREAM, 0);
if(hsock == -1){
printf("Error initializing socket %d\n",WSAGetLastError());
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
(setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
printf("Error setting options %d\n", WSAGetLastError());
free(p_int);
}
free(p_int);
//Bind and listen
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET ;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = INADDR_ANY ;
if( bind( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){
fprintf(stderr,"Error binding to socket, make sure nothing else is listening on this port %d\n",WSAGetLastError());
}
if(listen( hsock, 10) == -1 ){
fprintf(stderr, "Error listening %d\n",WSAGetLastError());
}
//Now lets to the server stuff
//*** Changed to be SOCKET instead of int*
SOCKET csock;
sockaddr_in sadr;
int addr_size = sizeof(SOCKADDR);
while(true){
printf("waiting for a connection\n");
//*** Changed to comment out line as it is not needed
// csock = (SOCKET)malloc(sizeof(SOCKET));
//*** Changed check to be INVALID_SOCKET
if((csock = accept( hsock, (SOCKADDR*)&sadr, &addr_size))!= INVALID_SOCKET ){
printf("Received connection from %s",inet_ntoa(sadr.sin_addr));
//*** Changed to pass the client socket
CreateThread(0,0,&SocketHandler, (void*)csock , 0,0);
}
else{
fprintf(stderr, "Error accepting %d\n",WSAGetLastError());
}
}
}
DWORD WINAPI SocketHandler(void* lp){
//** Changed to cast as the SOCKET which was passed
SOCKET csock = (SOCKET)lp;
char buffer[1024];
int buffer_len = 1024;
int bytecount;
memset(buffer, 0, buffer_len);
if((bytecount = recv(csock, buffer, buffer_len, 0))==SOCKET_ERROR){
fprintf(stderr, "Error receiving data %d\n", WSAGetLastError());
}
printf("Received bytes: %d\nReceived string: \"%s\"\n", bytecount, buffer);
char buff[1] = {0x11};
if((bytecount = send(csock, buff, 1, 0))==SOCKET_ERROR){
fprintf(stderr, "Error sending data %d\n", WSAGetLastError());
}
printf("Sent bytes: %d. Send Message: %s\n ", bytecount,buff);
//*** Changed to close the socket after the message is sent. Otherwise
//*** the socket would remain open
closesocket(csock);
//*** Changed to comment the line out as there is
//*** no allocated memory.
//free(csock);
return 0;
}