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;
}
}