在前几篇的博客中简单的介绍了一下 BSON 的使用方法,那么在这片文章中将介绍一下网络编程中,
如何使用 BSON 来在服务器和客户端收发消息结构。
本篇文章中的示例代码是基于前一篇文章中"[c++, linux]网络编程之 poll 的使用方法" 所编写的服务器端和客户端代码实现的。
代码结构
message_sender/
|-------------/utils/
|------ message.h
|-------------/client/
|----- client.cpp
|----- build.sh
|----- Makefile.am
|----- configure.in
|------------/server/
|----- server.cpp
|----- build.sh
|----- Makefile.am
|----- configure.in
示例代码
utils/message.h
-
#ifndef MESSAGE_H
-
#define MESSAGE_H
-
-
typedef struct msg_header
-
{
-
int len ;
-
-
msg_header() : len (0)
-
{}
-
-
} header_t;
-
-
typedef struct msg
-
{
-
header_t header ;
-
char data[0] ;
-
-
} message_t;
-
-
-
#endif // message.h
Client
1. build.sh
-
#!/bin/sh
-
-
autoscan
-
aclocal
-
autoconf
-
autoheader #after autoheader , create a Makefile.am then continue execute follow command
-
automake --add-missing
-
./configure CXXFLAGS= CFLAGS=
-
make
2.configure.in
-
# -*- Autoconf -*-
-
# Process this file with autoconf to produce a configure script.
-
-
AC_INIT(message_sender_client)
-
AC_CONFIG_SRCDIR([client.cpp])
-
AC_CONFIG_HEADERS([config.h])
-
-
AM_INIT_AUTOMAKE(message_sender_client, 1.0)
-
-
-
# Checks for programs.
-
AC_PROG_CXX
-
AC_PROG_CC
-
-
#add by Aimer , cause method use realloc
-
AC_FUNC_REALLOC
-
-
# Checks for header files.
-
AC_CHECK_HEADERS([arpa/inet.h netinet/in.h strings.h sys/socket.h unistd.h])
-
-
# Checks for typedefs, structures, and compiler characteristics.
-
AC_TYPE_SSIZE_T
-
-
# Checks for library functions.
-
AC_CHECK_FUNCS([bzero socket])
-
-
AC_OUTPUT(Makefile)
3.Makefile.am
-
AUTOMAKE_OPTIONS=foreign
-
bin_PROGRAMS=message_sender_client
-
-
#define short names for bson path and boost path
-
BSON_PATH=/unixC/Bson/bson/src
-
BOOST_PATH=/unixC/Boost/boost_1_58_0
-
-
message_sender_client_SOURCES=\
-
client.cpp \
-
$(BSON_PATH)/bsonobj.cpp $(BSON_PATH)/util/json.cpp \
-
$(BSON_PATH)/oid.cpp $(BSON_PATH)/lib/base64.cpp \
-
$(BSON_PATH)/lib/md5.cpp $(BSON_PATH)/lib/nonce.cpp
-
-
-
message_sender_client_CXXFLAGS=\
-
-I$(BOOST_PATH) -I$(BSON_PATH) \
-
-D_FILE_OFFSET_BITS=64 -ggdb -Wall -O0
-
-
message_sender_client_LDADD=\
-
-lpthread -lm -lboost_system -lboost_thread \
-
-lboost_thread -lboost_program_options -lrt
-
-
message_sender_client_LDFLAGS=\
-
-fPIC -rdynamic -L$(BOOST_PATH)/stage/lib -pthread
4.client.cpp
-
#include <cstdio> // perror
-
#include <cstring> // string
-
#include <strings.h> // memset
-
#include <iostream>
-
#include <sys/types.h> // AF_INET, SOCK_STREAM
-
#include <sys/socket.h> // socket , connect
-
#include <arpa/inet.h> // inet_aton
-
#include <netinet/in.h>
-
#include <unistd.h>
-
-
#include <bson.h> // BSONObj , BSONObjBuilder
-
-
#include "../utils/message.h" // struct message_t
-
-
#define SERVER_PORT 1027
-
#define SERVER_IP "10.0.2.15"
-
#define MAXLINE 1024*2
-
-
using namespace std ;
-
using namespace bson ;
-
-
// add method buildMessage here
-
/**
-
method :
-
int buildMessage ( char **ppBuffer[out], int *pBufferSize[out], BSONObj *obj[in] )
-
return :
-
0 if success building a message
-
-1 if failed building a message
-
*/
-
-
int buildMessage ( char **ppBuffer , int *pBufferSize , BSONObj *obj )
-
{
-
message_t *pMessage = NULL ;
-
int size = sizeof(message_t) ;
-
-
if ( obj != NULL )
-
size += obj->objsize() ;
-
-
if ( size > *pBufferSize )
-
{
-
*ppBuffer = (char*)realloc(*ppBuffer , size*sizeof(char)) ;
-
*pBufferSize = size ;
-
-
if ( *ppBuffer == NULL )
-
{
-
perror ("failed to realloc space for ppBuffer") ;
-
return -1 ;
-
}
-
}
-
-
pMessage = (message_t*)(*ppBuffer) ;
-
pMessage->header.len = size ;
-
-
if ( obj != NULL )
-
{
-
memcpy (&pMessage->data[0] , obj->objdata() , obj->objsize() ) ;
-
}
-
-
return 0 ;
-
}
-
-
-
int main ( int argc , char **argv )
-
{
-
char buf [MAXLINE] ;
-
ssize_t n ; // message content length
-
struct sockaddr_in server_addr ;
-
int connfd ;
-
int ret ;
-
string msg ;
-
-
connfd = socket (AF_INET , SOCK_STREAM , 0 ) ;
-
bzero (&server_addr , sizeof(struct sockaddr_in)) ;
-
-
server_addr.sin_family = AF_INET ;
-
server_addr.sin_port = htons (SERVER_PORT) ;
-
inet_aton (SERVER_IP , &server_addr.sin_addr ) ;
-
-
ret = connect ( connfd , (struct sockaddr*)&server_addr , sizeof(struct sockaddr_in) ) ;
-
-
-
if ( ret < 0 )
-
{
-
perror ("failed connect") ;
-
return -1;
-
}
-
-
cout << "input message "<< endl ;
-
cin >> msg ;
-
-
BSONObjBuilder builder ;
-
-
builder.append ("message data", msg.c_str ()) ;
-
-
BSONObj obj = builder.obj() ;
-
-
char *pBuffer = NULL ;
-
int pBufferSize = 0 ;
-
-
cout << obj.toString() << endl ;
-
-
cout << "-------- /test build message/ ------------"<<endl ;
-
-
buildMessage (&pBuffer , &pBufferSize , &obj) ;
-
-
// pBuffer content can not be seen on console
-
// cout << " here is the pBuffer content \n "<< pBuffer << endl ;
-
cout <<"message size " << pBufferSize << endl ;
-
cout << "message data size " << obj.objsize() << endl ;
-
cout << "message header size " << pBufferSize - obj.objsize() << endl ;
-
-
write (connfd , pBuffer , pBufferSize ) ;
-
-
-
return 0 ;
-
}
Server
1.build.sh
-
#!/bin/sh
-
-
autoscan
-
aclocal
-
autoconf
-
autoheader
-
automake --add-missing
-
./configure CXXFLAGS= CFLAGS=
-
make
2.configure.in
-
# -*- Autoconf -*-
-
# Process this file with autoconf to produce a configure script.
-
-
-
AC_INIT(message_sender_server)
-
-
AC_USE_SYSTEM_EXTENSIONS # we will use bson and boost
-
-
AM_INIT_AUTOMAKE(message_sender_server,1.0)
-
-
AC_CONFIG_SRCDIR([server.cpp])
-
-
AC_CONFIG_HEADERS([config.h])
-
-
# Checks for programs.
-
AC_PROG_CXX
-
-
AC_PROG_CC
-
-
# Checks for libraries.
-
-
# Checks for header files.
-
AC_CHECK_HEADERS([limits.h netdb.h netinet/in.h strings.h sys/socket.h unistd.h])
-
-
# Checks for typedefs, structures, and compiler characteristics.
-
AC_TYPE_SSIZE_T
-
-
# Checks for library functions.
-
AC_CHECK_FUNCS([bzero socket])
-
-
AC_OUTPUT(Makefile)
3.Makefile.am
-
AUTOMAKE_OPTIONS=foreign
-
bin_PROGRAMS=message_sender_server
-
-
BSON_PATH=/unixC/Bson/bson/src
-
BOOST_PATH=/unixC/Boost/boost_1_58_0
-
-
message_sender_server_SOURCES=\
-
server.cpp \
-
$(BSON_PATH)/bsonobj.cpp $(BSON_PATH)/util/json.cpp \
-
$(BSON_PATH)/oid.cpp $(BSON_PATH)/lib/base64.cpp \
-
$(BSON_PATH)/lib/md5.cpp $(BSON_PATH)/lib/nonce.cpp
-
-
message_sender_server_CXXFLAGS=\
-
-I$(BOOST_PATH) -I$(BSON_PATH) -D_FILE_OFFSET_BITS=64 \
-
-ggdb -Wall -O0
-
-
message_sender_server_LDADD=\
-
-lpthread -lm -lboost_system -lboost_thread \
-
-lboost_thread -lboost_program_options -lrt
-
-
message_sender_server_LDFLAGS=\
-
-fPIC -rdynamic -L$(BOOST_PATH)/stage/lib -pthread
4.server.cpp
-
#include <cstdio>
-
#include <limits.h>
-
#include <sys/types.h> // socket , bind , accept
-
#include <sys/socket.h> // socket , bind , socklen_t , accept
-
#include <poll.h> // poll, struct pollfd
-
#include <netdb.h> // socklen_t
-
#include <netinet/in.h> // struct sockaddr_in , sockaddr
-
#include <errno.h> // errno
-
#include <unistd.h> // read, write
-
#include <strings.h> // bzero
-
#include <iostream> // cout , endl , cin
-
-
#include <bson.h> // BSONObj
-
#include "../utils/message.h" // struct message_t
-
-
#define MAXLINE 1024*2
-
#define OPEN_MAX 1024
-
#define SERVER_PORT 1027
-
#define INFTIM 1024
-
-
using namespace std ;
-
using namespace bson ;
-
-
//add method parseMessage
-
/**
-
method :
-
this method is used to extract message's data
-
from char *pBuffer , into BSONObj this object
-
int parseMessage( char *pBuffer [in], BSONObj &msgData [out])
-
return:
-
0 : success extracting message data into BSONObj
-
-1: failed extracting message data into BSONObj
-
-
[in] : means this parameter is pass-in-value parameter
-
[out] : means this parameter is value-result which can
-
also be recognized as the return value of the method
-
*/
-
-
int parseMessage ( char *pBuffer, BSONObj &msgData )
-
{
-
if ( pBuffer == NULL )
-
{
-
perror ("message is invalid ") ;
-
return -1 ;
-
}
-
-
message_t *pMessage = (message_t*)(pBuffer) ;
-
-
if ( pMessage->header.len < sizeof(message_t) )
-
{
-
perror ("message content is invalid ") ;
-
return -1 ;
-
}
-
-
// cout << pMessage->header.len << endl ;
-
// cout << &pMessage->data[0] << endl ;
-
-
// BSONObjBuilder builder ;
-
// builder.append ("", &(pMessage->data[0])) ;
-
-
msgData = BSONObj(&pMessage->data[0]) ;
-
-
-
return 0 ;
-
}
-
-
-
int main ( int argc , char ** argv )
-
{
-
int i , maxi , listenfd , connfd , sockfd ;
-
int nready ;
-
ssize_t n ;
-
char buf[MAXLINE] ;
-
socklen_t client_len ;
-
struct pollfd client[OPEN_MAX] ;
-
struct sockaddr_in client_addr , server_addr ;
-
-
listenfd = socket ( AF_INET , SOCK_STREAM , 0 ) ;
-
bzero ( &server_addr , sizeof(struct sockaddr_in)) ;
-
-
server_addr.sin_family = AF_INET ;
-
server_addr.sin_addr.s_addr = htonl (INADDR_ANY) ;
-
server_addr.sin_port = htons ( SERVER_PORT ) ;
-
-
bind (listenfd , (struct sockaddr*)&server_addr ,
-
sizeof(struct sockaddr_in) ) ;
-
-
listen ( listenfd , 10 ) ;
-
-
client[0].fd = listenfd ;
-
client[0].events = POLLRDNORM ; // poll read normal
-
-
for ( i = 1 ; i < OPEN_MAX ; i++ )
-
{
-
client[i].fd = -1;
-
}
-
-
maxi = 0 ;
-
-
for ( ; ; )
-
{
-
nready = poll (client , maxi+1 , INFTIM) ;
-
-
if ( client[0].revents & POLLRDNORM )
-
{
-
// this means new client connection request come
-
client_len = sizeof( struct sockaddr_in ) ;
-
connfd = accept ( listenfd , (struct sockaddr*)&client_addr ,
-
&client_len ) ;
-
-
// updates maxi, and check if i out of limition of OPEN_MAX
-
for ( i = 1 ; i < OPEN_MAX ; i++ )
-
{
-
if ( client[i].fd < 0 )
-
{
-
client[i].fd = connfd ;
-
break ;
-
}
-
} // for
-
-
if ( i == OPEN_MAX )
-
{
-
perror ("too many client requests ") ;
-
return -1 ;
-
}
-
-
client[i].events = POLLRDNORM ;
-
-
if ( i > maxi )
-
maxi = i ;
-
-
if ( --nready <= 0 )
-
continue ;
-
} // if
-
-
for ( i = 1 ; i <= maxi ; i++ )
-
{
-
if ( ( sockfd = client[i].fd ) < 0 )
-
continue ; // continue the sub for cycle
-
-
if ( client[i].revents & (POLLRDNORM | POLLERR) )
-
{
-
if ( ( n = read(sockfd , buf , MAXLINE)) < 0 )
-
{
-
// read n < 0 , it must some error happen
-
// if client reset connection , release client[i].fd
-
// else return error code
-
if ( errno == ECONNRESET )
-
{
-
// this means client reset connection
-
close (sockfd) ;
-
client[i].fd = -1 ;
-
}
-
else
-
{
-
perror ("error when server read from client") ;
-
return -1 ;
-
}
-
-
}
-
else if ( n == 0 )
-
{
-
// this means client close connection
-
close (sockfd) ;
-
client[i].fd = -1 ;
-
}
-
else
-
{
-
-
//cout << "n = " << n << endl ;
-
-
BSONObj msgData ;
-
-
parseMessage (buf , msgData) ;
-
cout << msgData.toString() << endl ;
-
-
// n > 0 , server read something from client
-
// cout << "receive message len " << msgData.objsize() <<endl ;
-
}
-
-
} // if POLLRDNORM | POLLERROR
-
-
}// for
-
-
} // main cycle
-
-
return 0 ;
-
}
end
阅读(1627) | 评论(0) | 转发(0) |