TCP(传输控制协议)网络通信是常见的网络应用形式,它提供了面向连接的、可靠的数据传输服务。TCP通信常用的接口主要包括以下几个方面:
int socket(int domain, int type, int protocol);
type
:套接字类型,对于TCP协议,指定为SOCK_STREAM,表示面向流的传输协议。protocol
:传输层协议类型,对于TCP,通常指定为0。int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd
:由socket()返回的文件描述符。myaddr
:指向sockaddr结构体的指针,包含要绑定的地址和端口信息。addrlen
:地址结构体的长度。 int listen(int sockfd, int backlog);
sockfd
:服务器端的套接字描述符。backlog
:设置等待连接队列的最大长度。 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd
:服务器端的监听套接字描述符。addr
:可选参数,用于存储客户端的地址信息。addrlen
:传入时表示addr的长度,传出时表示实际存储的客户端地址信息的长度。 int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
sockfd
:客户端的套接字描述符。addr
:指向服务器地址信息的sockaddr结构体指针。addrlen
:服务器地址结构体的长度。 ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
send()
:用于向连接的套接字发送数据。recv()
:用于从连接的套接字接收数据。sockfd
:套接字描述符。buf
:指向数据缓冲区的指针。len
:要发送或接收的数据长度。flags
:通常设置为0,表示默认行为。send()
,成功时返回实际发送的字节数,失败时返回-1。recv()
,成功时返回实际接收的字节数,如果连接已关闭且没有数据可读,则返回0,出错时返回-1。 int close(int fd);
#include "TcpServer.hpp"
#include
int main(int argc, char *argv[])
{
if (argc != 2)
{
std::cerr << "Usage: " << argv[0] << " local-port" << std::endl;
exit(0);
}
uint16_t port = std::stoi(argv[1]);
std::unique_ptr tsvr = std::make_unique(port);
tsvr->Initserver();
tsvr->Loop();
return 0;
}
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include "InterAddr.hpp"
#include "Threadpool.hpp"
enum
{
SOCKET_ERROR = 1,
BIND_ERROR,
LISTEN_ERROR
};
static const uint16_t gport = 8888;
static const int glisten = -1;
static const int gbacklog = 8;
using task_t = std::function;
class Tcpserver
{
public:
Tcpserver(uint16_t port = gport)
: _port(port), _listensockfd(glisten), _isrunning(false)
{
}
void Initserver()
{
_listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);
if (_listensockfd < 0)
{
std::cout << "socket error" << std::endl;
exit(SOCKET_ERROR);
}
struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(_port);
local.sin_addr.s_addr = INADDR_ANY;
if (bind(_listensockfd, (const sockaddr *)&local, sizeof(local)) < 0)
{
std::cout << "bind error" << std::endl;
exit(BIND_ERROR);
}
if (::listen(_listensockfd, gbacklog) < 0)
{
std::cout << "listen error" << std::endl;
exit(LISTEN_ERROR);
}
std::cout << "init success" << std::endl;
}
void Loop()
{
_isrunning = true;
while (true)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int sockfd = ::accept(_listensockfd, (struct sockaddr *)&client, &len);
if (sockfd < 0)
{
std::cout << "accpet error" << std::endl;
exit(1);
}
InterAddr addr(client);
std::cout<<"get a new link, client info"<::GetInstance()->Equeue(f);
}
_isrunning = false;
}
void Service(int sockfd, InterAddr addr)
{
while (true)
{
char buffer[1024];
ssize_t m = ::read(sockfd, buffer, sizeof(buffer) - 1);
if (m > 0)
{
buffer[m] = 0;
std::string echoserver = "[server echo]#";
echoserver += buffer;
::write(sockfd, echoserver.c_str(), echoserver.size());
}
else if (m == 0)
{
std::cout << "clent quit " << addr.AddrStr() << std::endl;
break;
}
else
{
std::cout << "read error" << std::endl;
exit(1);
}
}
::close(sockfd);
}
~Tcpserver()
{
}
private:
uint16_t _port;
int _listensockfd;
bool _isrunning;
};
//interaddr.hpp
#pragma once
#include
#include
#include
#include
#include
#include
class InterAddr
{
private:
void ToHost(const struct sockaddr_in &addr)
{
port = ntohl(addr.sin_port);
ip = inet_ntoa(addr.sin_addr);
}
private:
std::string ip;
uint16_t port;
struct sockaddr_in _addr;
public:
InterAddr(const struct sockaddr_in &addr)
: _addr(addr)
{
ToHost(addr);
}
bool operator == (const InterAddr &t)
{
return (this->ip == t.ip && this->port == t.port);
}
std::string Ip()
{
return ip;
}
uint16_t Port()
{
return port;
}
struct sockaddr_in Addr()
{
return _addr;
}
std::string AddrStr()
{
return ip + ":" + std::to_string(port);
}
~InterAddr()
{
}
};
//LockGuard.hpp
#pragma once
#include
class LockGuard
{
private:
/* data */
pthread_mutex_t* _mutex;
public:
LockGuard(pthread_mutex_t* mutex);
~LockGuard();
};
LockGuard::LockGuard(pthread_mutex_t* mutex):_mutex(mutex)
{
pthread_mutex_lock(_mutex);
}
LockGuard::~LockGuard()
{
pthread_mutex_unlock(_mutex);
}
//Thread.hpp
#pragma once
#include
#include
#include
#include
namespace ThreadMoudle
{
using func_t = std::function;
class Thread
{
public:
void Execute()
{
isrunning = true;
_func(_name);
isrunning = false;
}
public:
Thread(const std::string name, func_t func)
: _name(name), _func(func)
{
}
static void *ThreadRoutine(void *args)
{
Thread *a = static_cast(args);
a->Execute();
return nullptr;
}
bool Start()
{
int n = pthread_create(&_tid, nullptr, ThreadRoutine, (void *)this);
if (n != 0)
{
return false;
}
else
{
return true;
}
}
std::string Status()
{
if (isrunning)
{
return "running";
}
else
{
return "stop";
}
}
void Stop()
{
if (isrunning)
{
pthread_cancel(_tid);
isrunning = false;
}
}
void Join()
{
pthread_join(_tid, nullptr);
}
std::string Name()
{
return _name;
}
~Thread()
{
}
private:
std::string _name;
pthread_t _tid;
bool isrunning;
func_t _func;
};
}
//Threadpool.hpp
#pragma once
#include
#include
#include
#include
#include
#include
#include "LockGuard.hpp"
#include "Thread.hpp"
using namespace ThreadMoudle;
static const int gdefaultnum = 5;
// pthread_mutex_t _fmtx=PTHREAD_MUTEX_INITIALIZER;
template
class ThreadPool
{
private:
void LockQueue()
{
pthread_mutex_lock(&_mutex);
}
void UnlockQueue()
{
pthread_mutex_unlock(&_mutex);
}
void Wakeup()
{
pthread_cond_signal(&_cond);
}
void WakeupAll()
{
pthread_cond_broadcast(&_cond);
}
void Sleep()
{
pthread_cond_wait(&_cond,&_mutex);
}
bool IsEmpty()
{
return _task_queue.empty();
}
void HandlerTask(const std::string name)
{
while (1)
{
LockQueue();
while (IsEmpty() && _isrunning)
{
sleep_thread_num++;
Sleep();
sleep_thread_num--;
}
if (IsEmpty() && !_isrunning)
{
UnlockQueue();
break;
}
T t = _task_queue.front();
// std::cout<<&t< &) = delete;
void operator=(const ThreadPool &) = delete;
public:
void Stop()
{
LockQueue();
_isrunning = false;
WakeupAll();
UnlockQueue();
}
static ThreadPool *GetInstance()
{
LockGuard lockguard(&_sig_mutex);
if (_tp == nullptr)
{
_tp = new ThreadPool();
_tp->Init();
_tp->Start();
}
return _tp;
}
void Equeue(const T& in)
{
LockQueue();
if (_isrunning)
{
_task_queue.push(in);
if (sleep_thread_num > 0)
{
Wakeup();
}
}
UnlockQueue();
}
~ThreadPool()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond);
}
private:
int _thread_num;
std::vector _threads;
std::queue _task_queue;
bool _isrunning;
int sleep_thread_num;
pthread_mutex_t _mutex;
pthread_cond_t _cond;
static ThreadPool *_tp;
static pthread_mutex_t _sig_mutex;
};
template
ThreadPool *ThreadPool::_tp = nullptr;
template
pthread_mutex_t ThreadPool::_sig_mutex = PTHREAD_MUTEX_INITIALIZER;
#include
#include
#include
#include
#include
#include
#include
#include
#include "InterAddr.hpp"
int main(int argc, char *argv[])
{
if (argc != 3)
{
std::cerr << "Usage: " << argv[0] << "server-ip local-port" << std::endl;
exit(0);
}
std::string serverip = argv[1];
uint16_t port = std::stoi(argv[2]);
int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
std::cerr << "socket error" << std::endl;
exit(1);
}
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (::inet_pton(AF_INET, serverip.c_str(), &server.sin_addr.s_addr) <= 0)
{
std::cerr << "inet_pton error" << std::endl;
exit(1);
}
if (::connect(sockfd, (const struct sockaddr *)&server, sizeof(server)) < 0)
{
std::cerr << "connect error" << std::endl;
exit(1);
}
while (true)
{
std::string message;
std::cout<<"Enter #";
std::getline(std::cin,message);
::write(sockfd,message.c_str(),message.size());
char buffer[1024];
int n=::read(sockfd,buffer,sizeof(buffer));
if(n > 0)
{
buffer[n] = 0;
std::cout << buffer << std::endl;
}
else
{
break;
}
}
::close(sockfd);
return 0;
}