socket编程实现TCP通信
tcp_client.cc
c
复制代码
#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
c
复制代码
#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
c
复制代码
#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);//不理会子进程 v2.1
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);
// 获取连接成功,开始通信服务
// v1 单进程循环
//service(servicesock, client_ip, client_port);
//v2.0 多进程
// pid_t id = fork();
// if(id == 0)
// {
// close(_listensock);
// service(servicesock, client_ip, client_port);
// exit(0);
// }
// close(servicesock);
//v2.1 多进程
// pid_t id = fork();
// if(id == 0)
// {
// close(_listensock);
// if(fork() > 0) exit(0);
// service(servicesock, client_ip, client_port);
// }
// waitpid(id,nullptr,0);
// close(servicesock);
//v3 多线程
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
c
复制代码
#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
makefile
复制代码
.PHONY:add
all:tcp_client tcp_server
tcp_client:tcp_client.cc
g++ -o $@ $^ -std=c++11 -l pthread
tcp_server:tcp_server.cc
g++ -o $@ $^ -std=c++11 -l pthread
.PHONY:clean
clean:
rm -f tcp_client tcp_server