socket编程实现TCP通信
tcp_client.cc
# include <iostream>
# include <cstring>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <pthread.h>
# include <unistd.h>
# include <cerrno>
# include "log.hpp"
# define SIZE 1024
uint16_t serverport;
std:: string serverip;
void * tcpSend ( void * args)
{ int sock = * ( int * ) args; std:: string message; while ( true) { std:: cerr << "请输入你的信息# " ; std:: getline ( std:: cin, message) ; send ( sock, message. c_str ( ) , message. size ( ) , 0 ) ; }
} void * tcpRecv ( void * args)
{ int sock = * ( int * ) args; char buff[ 1024 ] ; while ( true) { ssize_t s = recv ( sock, buff, sizeof ( buff) - 1 , 0 ) ; if ( s > 0 ) { buff[ s] = '\0' ; printf ( "%s\n" , buff) ; fflush ( stdout ) ; } }
}
int main ( int argc, char * argv[ ] )
{ if ( argc != 3 ) { std:: cout << "Usage: " << argv[ 0 ] << " ip port" << std:: endl; exit ( 1 ) ; } int sock = socket ( AF_INET, SOCK_STREAM, 0 ) ; if ( sock < 0 ) { std:: cerr << "FATAL " << errno << ":" << strerror ( errno) ; exit ( 2 ) ; } serverport = atoi ( argv[ 2 ] ) ; serverip = argv[ 1 ] ; struct sockaddr_in server; memset ( & server, 0 , sizeof server) ; server. sin_family = AF_INET; server. sin_port = htons ( serverport) ; server. sin_addr. s_addr = inet_addr ( serverip. c_str ( ) ) ; if ( connect ( sock, ( struct sockaddr * ) & server, sizeof ( server) ) == - 1 ) { printf ( "连接失败 [%d:%s]\n" , errno, strerror ( errno) ) ; close ( sock) ; exit ( 1 ) ; } LogMessage ( NORMAL, "connect success" ) ; pthread_t t1, t2; pthread_create ( & t1, nullptr, tcpSend, ( void * ) & sock) ; pthread_create ( & t2, nullptr, tcpRecv, ( void * ) & sock) ; pthread_join ( t1, nullptr) ; pthread_join ( t2, nullptr) ; close ( sock) ; return 0 ;
}
tcp_server.cc
# include "tcp_server.hpp"
int main ( int argc, char * argv[ ] )
{ if ( argc != 2 ) { std:: cout<< "Usage: " << argv[ 0 ] << " port" << std:: endl; exit ( 1 ) ; } uint16_t port = atoi ( argv[ 1 ] ) ; TcpServer* svr = new TcpServer ( port) ; svr-> initServer ( ) ; svr-> start ( ) ; delete svr; return 0 ;
}
tcp_server.hpp
# ifndef UDP_SERVER_HPP
# define UDP_SERVER_HPP # include <iostream>
# include <cstring>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <unordered_map>
# include <unistd.h>
# include <signal.h>
# include <wait.h>
# include "log.hpp" # define SIZE 1024 static void service ( int sock, std:: string & client_ip, uint16_t & client_port)
{ char buff[ 1024 ] ; while ( true) { ssize_t s = read ( sock, buff, sizeof ( buff) - 1 ) ; if ( s > 0 ) { buff[ s] = '\0' ; printf ( "[%s:%d]# %s\n" , client_ip. c_str ( ) , client_port, buff) ; } else if ( s == 0 ) { LogMessage ( NORMAL, "[%s:%d] shutdown, me too!" , client_ip. c_str ( ) , client_port) ; break ; } else { LogMessage ( ERROR, "read socket error, %d:%s" , errno, strerror ( errno) ) ; break ; } write ( sock, buff, strlen ( buff) ) ; }
}
struct ThreadData
{ int _sock; std:: string _ip; uint16_t _port;
} ;
class TcpServer
{
private: const int gbacklog = 20 ; public: static void * threadRoutine ( void * args) { pthread_detach ( pthread_self ( ) ) ; ThreadData* td = ( ThreadData* ) args; service ( td-> _sock, td-> _ip, td-> _port) ; delete td; return nullptr; } TcpServer ( uint16_t port, std:: string ip = "0.0.0.0" ) : _port ( port) , _listensock ( - 1 ) , _ip ( ip) { } void initServer ( ) { _listensock = socket ( AF_INET, SOCK_STREAM, 0 ) ; if ( _listensock < 0 ) { LogMessage ( FATAL, "socket error, %d:%s" , errno, strerror ( errno) ) ; exit ( 2 ) ; } struct sockaddr_in local; local. sin_family = AF_INET; local. sin_port = htons ( _port) ; local. sin_addr. s_addr = inet_addr ( _ip. c_str ( ) ) ; if ( bind ( _listensock, ( struct sockaddr * ) & local, sizeof ( local) ) < 0 ) { LogMessage ( FATAL, "bind error, %d:%s" , errno, strerror ( errno) ) ; exit ( 3 ) ; } if ( listen ( _listensock, gbacklog) < 0 ) { LogMessage ( FATAL, "listen error, %d:%s" , errno, strerror ( errno) ) ; exit ( 4 ) ; } LogMessage ( NORMAL, "init TCP server success, listensock: %d" , _listensock) ; } void start ( ) { signal ( SIGCHLD, SIG_IGN) ; while ( true) { struct sockaddr_in src; socklen_t len = sizeof ( src) ; int servicesock = accept ( _listensock, ( struct sockaddr * ) & src, & len) ; std:: cout<< servicesock<< std:: endl; if ( servicesock < 0 ) { LogMessage ( ERROR, "accept error, %d:%s" , errno, strerror ( errno) ) ; continue ; } uint16_t client_port = ntohs ( src. sin_port) ; std:: string client_ip = inet_ntoa ( src. sin_addr) ; LogMessage ( NORMAL, "link success, [%s:%d]" , client_ip. c_str ( ) , client_port) ; ThreadData* td = new ThreadData; td-> _sock = servicesock; td-> _ip = client_ip; td-> _port = client_port; pthread_t tid; pthread_create ( & tid, nullptr, threadRoutine, ( void * ) td) ; close ( servicesock) ; } } private: uint16_t _port; std:: string _ip; int _listensock;
} ;
# endif
log.hpp
# pragma once
# include <iostream>
# include <cstdio>
# include <cstdarg>
# include <ctime>
# include <string> # define DEBUG 0
# define NORMAL 1
# define WARNING 2
# define ERROR 3
# define FATAL 4
const char * gLevelMap[ ] = { "DEBUG" , "NORMAL" , "WARNING" , "ERROR" , "FATAL" } ; void LogMessage ( int level, const char * format, . . . )
{ char stdBuffer[ 1024 ] = { '\0' } ; time_t timestamp = time ( nullptr) ; snprintf ( stdBuffer, sizeof stdBuffer, "[%s] [%ld]" , gLevelMap[ level] , timestamp) ; char logBuffer[ 1024 ] = { '\0' } ; ; va_list args; va_start ( args, format) ; vsnprintf ( logBuffer, sizeof logBuffer, format, args) ; va_end ( args) ; printf ( "%s%s\n" , stdBuffer, logBuffer) ;
}
makefile
.PHONY:add
all:tcp_client tcp_server
tcp_client:tcp_client.ccg++ -o $@ $^ -std=c++11 -l pthread
tcp_server:tcp_server.ccg++ -o $@ $^ -std=c++11 -l pthread
.PHONY:clean
clean:rm -f tcp_client tcp_server