目录
简单的UDP网络程序 1.1 UdpServer.hpp 1.2 UdpClient.cc 1.3 main.cc 1.4 makefile 1.5 log.hpp
简单的UDP网络程序
1.1 UdpServer.hpp
# pragma once
# include <iostream>
using namespace std;
# include <unistd.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <arpa/inet.h>
# include <netinet/in.h>
# include "log.hpp"
# include <strings.h>
# include <functional>
# include <cstring>
# include <unordered_map>
const static int NUM = 1024 ;
const static string DEFAULT_IP = "0.0.0.0" ;
const static uint16_t DEFAULT_PORT= 8080 ;
using func_t= function< string ( string) > ;
Log log;
class UdpServer
{
public :
UdpServer ( func_t func, uint16_t port= DEFAULT_PORT, string ip = DEFAULT_IP)
: _ip ( ip) , _port ( port) , _sockid ( - 1 ) , _func ( func)
{
}
~ UdpServer ( )
{
if ( _sockid > 0 )
{
close ( _sockid) ;
}
}
void Init ( )
{
_sockid = socket ( AF_INET, SOCK_DGRAM, 0 ) ;
if ( _sockid < 0 )
{
log ( Fatal, "socket failed" ) ;
exit ( 2 ) ;
}
log ( Info, "create socket successful, sockid:%d" , _sockid) ;
struct sockaddr_in local;
bzero ( & local, sizeof ( local) ) ;
local. sin_family = AF_INET;
local. sin_port = htons ( _port) ;
local. sin_addr. s_addr = INADDR_ANY;
if ( bind ( _sockid, ( struct sockaddr * ) & local, sizeof ( local) ) < 0 )
{
log ( Fatal, "bind failed, errno:%d, error code:%s" , errno, strerror ( errno) ) ;
exit ( 3 ) ;
}
log ( Info, "Server bind successful" ) ;
}
void CheckUser ( const struct sockaddr_in & client)
{
string clientIp= inet_ntoa ( client. sin_addr) ;
auto it= _online_client. find ( clientIp) ;
if ( it== _online_client. end ( ) )
{
_online_client. insert ( { clientIp, client} ) ;
std:: cout << "[" << clientIp << ":" << ntohs ( client. sin_port) << "] add to online user." << std:: endl;
}
}
void BroadCast ( const string& info, const string& clientip, const uint16_t & clientport)
{
for ( const auto & it: _online_client)
{
string message= "client" ;
message+= '[' ;
message+= "clientip:" ;
message+= clientip;
message+= ' ' ;
message+= "clientport" ;
message+= ":" ;
message+= to_string ( clientport) ;
message+= "]# " ;
message+= info;
sendto ( _sockid, message. c_str ( ) , message. size ( ) , 0 , ( struct sockaddr * ) ( & it. second) , sizeof ( it. second) ) ;
}
}
void Run ( )
{
struct sockaddr_in client;
socklen_t len = sizeof ( client) ;
bzero ( & client, sizeof ( client) ) ;
char buffer[ NUM] ;
bzero ( buffer, sizeof ( buffer) ) ;
while ( true )
{
ssize_t s = recvfrom ( _sockid, buffer, sizeof ( buffer) - 1 , 0 , ( struct sockaddr * ) & client, & len) ;
if ( s > 0 )
{
buffer[ s] = '\0' ;
char * clientip= inet_ntoa ( client. sin_addr) ;
CheckUser ( client) ;
cout << "client[ip:" << clientip<< " port:" << ntohs ( client. sin_port) << "]# " << buffer << endl;
uint16_t clientport= ntohs ( client. sin_port) ;
BroadCast ( buffer, clientip, clientport) ;
}
else if ( s== 0 )
{
log ( Warning, "client quit..." ) ;
break ;
}
else
{
log ( Fatal, "recvfrom failed..." ) ;
break ;
}
}
}
private :
string _ip;
uint16_t _port;
int _sockid;
func_t _func;
unordered_map< string, struct sockaddr_in > _online_client;
} ;
1.2 UdpClient.cc
# include <iostream>
using namespace std;
# include <unistd.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <arpa/inet.h>
# include <netinet/in.h>
# include <strings.h>
# include <pthread.h>
# include <cstring>
const static int NUM = 1024 ;
void Usage ( string argv)
{
cout << "\n\t"
<< "Usage:" << argv << " ServerIp ServerPort" << endl<< endl;
}
struct ThreadData
{
int sockid;
struct sockaddr_in server;
string ip;
} ;
void * recver_message ( void * argv)
{
pthread_detach ( pthread_self ( ) ) ;
ThreadData* td= static_cast < ThreadData* > ( argv) ;
char buffer[ 4096 ] ;
memset ( buffer, 0 , sizeof ( buffer) ) ;
while ( true )
{
struct sockaddr_in t;
socklen_t len= sizeof ( t) ;
ssize_t s= recvfrom ( td-> sockid, buffer, sizeof ( buffer) - 1 , 0 , ( struct sockaddr * ) & t, & len) ;
string tip= inet_ntoa ( t. sin_addr) ;
if ( s> 0 )
{
buffer[ s] = '\0' ;
printf ( "server[ip:%s,port:%d]# %s\n" , tip. c_str ( ) , ntohs ( t. sin_port) , buffer) ;
}
}
return nullptr ;
}
void * sender_message ( void * argv)
{
pthread_detach ( pthread_self ( ) ) ;
ThreadData* td= static_cast < ThreadData* > ( argv) ;
std:: string welcome = td-> ip;
welcome += " comming..." ;
sendto ( td-> sockid, welcome. c_str ( ) , welcome. size ( ) , 0 , ( struct sockaddr * ) & ( td-> server) , sizeof ( td-> server) ) ;
string buffer;
while ( true )
{
cerr<< "Please Enter# " ;
getline ( cin, buffer) ;
sendto ( td-> sockid, buffer. c_str ( ) , buffer. size ( ) , 0 , ( struct sockaddr * ) ( & ( td-> server) ) , sizeof ( td-> server) ) ;
}
return nullptr ;
}
int main ( int argc, char * argv[ ] )
{
if ( argc != 3 )
{
Usage ( argv[ 0 ] ) ;
exit ( 1 ) ;
}
string ServerIp= argv[ 1 ] ;
string str = argv[ 2 ] ;
uint16_t ServerPort = ( uint16_t ) stoi ( str. c_str ( ) ) ;
ThreadData td;
int sockid= socket ( AF_INET, SOCK_DGRAM, 0 ) ;
td. server. sin_family = AF_INET;
td. server. sin_addr. s_addr= inet_addr ( ServerIp. c_str ( ) ) ;
td. server. sin_port= htons ( ServerPort) ;
td. ip= ServerIp;
td. sockid= sockid;
socklen_t len= sizeof ( td. server) ;
pthread_t recver, sender;
pthread_create ( & recver, nullptr , recver_message, & td) ;
pthread_create ( & sender, nullptr , sender_message, & td) ;
while ( true )
{
sleep ( 1 ) ;
}
close ( sockid) ;
}
1.3 main.cc
# include <iostream>
using namespace std;
# include <string>
# include "UdpServer.hpp"
# include <vector>
# include <memory>
void Usage ( string argv)
{
cout << "\n\t"
<< "Usage:" << argv << " ServerPort" << endl
<< endl;
}
string func ( string s)
{
return s + " already handled\n" ;
}
bool SafeCheck ( const string & cmd)
{
vector< string> key_word = { "rm" , "mv" , "cp" , "kill" , "sudo" , "unlink" , "uninstall" ,
"yum" , "top" , "while" } ;
for ( const auto & s: key_word)
{
auto pos = cmd. find ( s) ;
if ( pos!= string:: npos)
{
return false ;
}
}
return true ;
}
string ExcuteCommand ( string cmd)
{
if ( ! SafeCheck ( cmd) )
{
return "bad man\n" ;
}
FILE * p = popen ( cmd. c_str ( ) , "r" ) ;
if ( nullptr == p)
{
perror ( "popen failed" ) ;
exit ( 5 ) ;
}
string ret= "\n" ;
char buffer[ 4096 ] ;
while ( true )
{
char * s = fgets ( buffer, sizeof ( buffer) - 1 , p) ;
if ( nullptr == s)
{
break ;
}
ret += buffer;
}
pclose ( p) ;
return ret;
}
int main ( int argc, char * argv[ ] )
{
if ( argc != 2 )
{
Usage ( argv[ 0 ] ) ;
exit ( 1 ) ;
}
string str = argv[ 1 ] ;
uint16_t ServerPort = ( uint16_t ) stoi ( str. c_str ( ) ) ;
unique_ptr< UdpServer> svr ( new UdpServer ( func, ServerPort) ) ;
svr-> Init ( ) ;
svr-> Run ( ) ;
return 0 ;
}
1.4 makefile
. PHONY: all
all: Client Server
Client: UdpClient. cc
g++ - o $@ $^ - std= c++ 11 - lpthread
Server: main. cc
g++ - o $@ $^ - std= c++ 11 - lpthread
. PHONY: clean
clean:
rm - f Client Server
1.5 log.hpp
# pragma once
# include <iostream>
using namespace std;
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
# include <fcntl.h>
# include <string>
# include <time.h>
# include <stdarg.h>
# define Info 0
# define Debug 1
# define Warning 2
# define Error 3
# define Fatal 4
# define Screen 1
# define OneFile 2
# define Classfile 3
# define SIZE 1024
# define LogFile "log.txt"
class Log
{
public :
Log ( )
{
printMethod = Screen;
path = "./log/" ;
}
void Enable ( int mothod)
{
printMethod = mothod;
}
string LevelToString ( int level)
{
switch ( level)
{
case Info:
{
return "Info" ;
}
case Debug:
{
return "Debug" ;
}
case Warning:
{
return "Warning" ;
}
case Error:
{
return "Error" ;
}
case Fatal:
{
return "Fatal" ;
}
default :
{
return "None" ;
}
}
}
void printlog ( int level, const string& logtxt)
{
switch ( printMethod)
{
case Screen:
{
cout<< logtxt<< endl;
break ;
}
case OneFile:
{
PrintOneFile ( LogFile, logtxt) ;
break ;
}
case Classfile:
{
PrintClassfile ( level, logtxt) ;
break ;
}
default :
{
break ;
}
}
}
void PrintOneFile ( const string& logname, const string& logtxt)
{
string _logname= path+ logname;
int fd= open ( _logname. c_str ( ) , O_WRONLY| O_CREAT| O_APPEND, 0666 ) ;
if ( fd< 0 )
{
perror ( "open fail" ) ;
return ;
}
write ( fd, logtxt. c_str ( ) , logtxt. size ( ) ) ;
close ( fd) ;
}
void PrintClassfile ( int level, const string& logtxt)
{
string filename= LogFile;
filename+= '.' ;
filename+= LevelToString ( level) ;
PrintOneFile ( filename, logtxt) ;
}
void operator ( ) ( int level, const char * format, . . . )
{
time_t t= time ( nullptr ) ;
struct tm * ctime= localtime ( & t) ;
char leftbuffer[ SIZE] ;
snprintf ( leftbuffer, SIZE, "[%s][%d-%d-%d %d:%d:%d]" , LevelToString ( level) . c_str ( ) ,
ctime-> tm_year+ 1900 , ctime-> tm_mon+ 1 , ctime-> tm_mday,
ctime-> tm_hour, ctime-> tm_min, ctime-> tm_sec) ;
va_list s;
va_start ( s, format) ;
char rightbuffer[ SIZE] = { 0 } ;
vsnprintf ( rightbuffer, SIZE, format, s) ;
va_end ( s) ;
char logtxt[ SIZE* 2 ] ;
snprintf ( logtxt, sizeof ( logtxt) , "%s %s" , leftbuffer, rightbuffer) ;
printlog ( level, logtxt) ;
}
~ Log ( )
{
}
private :
int printMethod;
string path;
} ;