demo源码 套接字初步封装部分¶
这部分东西都在注释里了,唯一值得注意的是Server类的start函数基本上代表了一个TCP server的典型工作流程了。 其他没什么好讲的,记录一点值得改进的地方:应该单独弄个Guard类封装一下mutex锁的,这样调用构造函数就可以加锁,局部函数结束系统调用析构函数自动除锁,比现在处处在返回值前面加个除锁语句简单太多了,第一次写这么大的项目没经验,下次再补上。
socket.h
#ifndef _SOCKET_H_
#define _SOCKET_H_
#include <stdint.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <string>
#include <fcntl.h>
#define INVALID_FD(fd) (fd < 0)
namespace Socket
{
// 设置套接字非阻塞
// param: sockfd/套接字描述符 en/是否非阻塞
int set_nonblock(int sockfd, bool en){
int flags = fcntl(sockfd, F_GETFL, 0);
if(en)
flags |= O_NONBLOCK;
else
flags &=~ O_NONBLOCK;
return fcntl(sockfd, F_SETFL, flags);
}
// 转换字符串ipv4地址
// param: addr/字符串ipv4地址 port/端口 sockaddr/存放ipv4地址
int convert_inaddr(const std::string &addr, uint16_t port, struct sockaddr_in &sockaddr){
bzero((void *)&sockaddr, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
if(inet_aton(addr.c_str(), &sockaddr.sin_addr) < 0)
return -1;
return 0;
}
class ISocket
{
public:
virtual ~ISocket(){};
// 获取套接字描述符
// param: void
// return: 套接字描述符
virtual int fd() = 0;
};
class Client: public ISocket
{
public:
Client();
Client(int fd);
~Client();
int fd();
int start();
int close();
int set_nonblock(bool nonblock);
int connect(const std::string &addr, uint16_t port);
ssize_t recv(void *buf, size_t len, int flags = 0);
ssize_t send(const void *buf, size_t len, int flags = 0);
private:
int m_sockfd;
pthread_mutex_t m_socketmutex;
};
class Server: public ISocket
{
public:
Server(const std::string &addr, uint16_t port);
~Server();
int set_nonblock(bool nonblock);
int fd();
int start(size_t backlog);
int close();
bool isclose();
Client *accept();
private:
std::string m_addr;
uint16_t m_port;
int m_sockfd;
pthread_mutex_t m_socketmutex;
};
}
#endif
socket.cpp
#include"socket.h"
namespace Socket
{
Client::Client(): m_sockfd(-1)
{
}
Client::Client(int fd): m_sockfd(fd)
{
}
Client::~Client()
{
close();
}
int Client::fd()
{
return m_sockfd;
}
int Client::start()
{
pthread_mutex_lock(&m_socketmutex);
if(!INVALID_FD(m_sockfd)){
pthread_mutex_unlock(&m_socketmutex);
return 0;
}
m_sockfd = socket(AF_INET, SOCK_STREAM, 0);
pthread_mutex_unlock(&m_socketmutex);
return 0;
}
int Client::close()
{
pthread_mutex_lock(&m_socketmutex);
if(INVALID_FD(m_sockfd)){
pthread_mutex_unlock(&m_socketmutex);
return 0;
}
int ret = ::close(m_sockfd);
if(ret == 0x00)
m_sockfd = -1;
pthread_mutex_unlock(&m_socketmutex);
return ret;
}
int Client::set_nonblock(bool nonblock)
{
pthread_mutex_lock(&m_socketmutex);
if(INVALID_FD(m_sockfd)){
pthread_mutex_unlock(&m_socketmutex);
return 0;
}
return Socket::set_nonblock(m_sockfd, nonblock);
}
int Client::connect(const std::string &addr, uint16_t port)
{
pthread_mutex_lock(&m_socketmutex);
if(INVALID_FD(m_sockfd)){
pthread_mutex_unlock(&m_socketmutex);
return 0;
}
struct sockaddr_in sockaddr;
bzero((void *)&sockaddr, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
inet_aton(addr.c_str(), &sockaddr.sin_addr) ;
::connect(m_sockfd, (struct sockaddr *)(&sockaddr), sizeof(sockaddr));
pthread_mutex_unlock(&m_socketmutex);
return 0;
}
ssize_t Client::recv(void *buf, size_t len, int flags)
{
pthread_mutex_lock(&m_socketmutex);
if(INVALID_FD(m_sockfd)) {
pthread_mutex_unlock(&m_socketmutex);
return -1;
}
pthread_mutex_unlock(&m_socketmutex);
return ::recv(m_sockfd, buf, len, 0);
}
ssize_t Client::send(const void *buf, size_t len, int flags)
{
pthread_mutex_lock(&m_socketmutex);
if(INVALID_FD(m_sockfd)){
pthread_mutex_unlock(&m_socketmutex);
return -1;
}
size_t nsend = 0x00;
ssize_t ret = 0x00;
do{
ret = ::send(m_sockfd, (uint8_t *)buf + nsend, len - nsend, 0);
if(ret < 0x00){
if(errno != EINTR){
pthread_mutex_unlock(&m_socketmutex);
return ret;
}
else
continue;
}
nsend += ret;
}while(nsend != len);
pthread_mutex_unlock(&m_socketmutex);
return nsend;
}
Server::Server(const std::string &addr, uint16_t port):
m_addr(addr), m_port(port), m_sockfd(-1)
{
}
Server::~Server()
{
close(); // ignore error
}
int Server::fd()
{
return m_sockfd;
}
int Server::set_nonblock(bool nonblock)
{
pthread_mutex_lock(&m_socketmutex);
if(INVALID_FD(m_sockfd)) {
pthread_mutex_unlock(&m_socketmutex);
return -1;
}
pthread_mutex_unlock(&m_socketmutex);
return Socket::set_nonblock(m_sockfd, nonblock);
}
int Server::close()
{
pthread_mutex_lock(&m_socketmutex);
::close(m_sockfd) ;
m_sockfd = -1;
pthread_mutex_unlock(&m_socketmutex);
return 0;
}
bool Server::isclose()
{
pthread_mutex_lock(&m_socketmutex);
if(INVALID_FD(m_sockfd)){
pthread_mutex_unlock(&m_socketmutex);
return true;
}
pthread_mutex_unlock(&m_socketmutex);
return false;
}
int Server::start(size_t backlog)
{
pthread_mutex_lock(&m_socketmutex);
struct sockaddr_in sockaddr;
convert_inaddr(m_addr, m_port, sockaddr);
int sockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
int enable = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&enable, sizeof(enable));//设置端口复用
bind(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
listen(sockfd, backlog);
m_sockfd = sockfd;
pthread_mutex_unlock(&m_socketmutex);
return 0;
}
Client *Server::accept()
{
pthread_mutex_lock(&m_socketmutex);
if(INVALID_FD(m_sockfd)){
pthread_mutex_unlock(&m_socketmutex);
return NULL;
}
struct sockaddr_in clientaddr;
socklen_t clientaddrlen = sizeof(clientaddr);
int clientfd = ::accept(m_sockfd, (struct sockaddr *)&clientaddr, &clientaddrlen);
if(INVALID_FD(clientfd))
return NULL;
Client *client = new Client(clientfd);
pthread_mutex_unlock(&m_socketmutex);
return client;
}
}