socket操作封装

socket操作封装

本文将unix中的socket相关操作进行封装,使得对socket的调用更加方便、直观

头文件SocketHel.h

#ifndef SOCKETSHEL__H__
#define SOCKETSHEL__H__

#include <arpa/inet.h>
#include <cstring> //memset


void setnbAndcoeHel(int socketfd);
int createNonblockingHel(int port);

void setnbAndcoeHel(int socketfd);
int createNonblockingHel(int port);
void bindHel(int socketfd,const struct sockaddr* addr);
void listenHel(int socketfd);
int acceptHel(int socketfd,struct sockaddr_in* addr);
int connectHel(int socketfd,const struct sockaddr* addr);
size_t readHel(int socketfd,void *buf,size_t count);
ssize_t readvHel(int socketfd,const struct iovec *iov,int iovcnt);
ssize_t writeHel(int socketfd,const void *buf,size_t count);
void closeHel(int socketfd);
void closeWriteHel(int socketfd);

void ipport_stctos(char *ip,size_t size,const struct sockaddr* addr);
void ip_stctos(char *ip,size_t size,const struct sockaddr* addr);

void ipport_stostc(const char *ip,uint16_t port,struct sockaddr_in* addr);

int getSocketError(int socketfd);

const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr);
const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr);

struct sockaddr* sockaddr_cast(struct sockaddr_in* addr);
struct sockaddr_in* sockaddr_in_cast(struct sockaddr* addr);

bool isSelfConnect(int socketfd);
struct sockaddr_in getLocalAddr(int socketfd);
struct sockaddr_in getPeerAddr(int socketfd);

源代码文件SocketHel.cpp

1) 用到的头文件

#include "SocketsHel.h"
#include "Types.h"


#include <cstring> // strlen,memset

#include <cassert> //assert
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdint.h>
#include <endian.h>

2) sockaddr* 和sockaddr_in* 的转化

const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr){
	return static_cast<const struct sockaddr*>(implicit_cast<const void*>(addr));
}
const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr){
	return static_cast<const struct sockaddr_in*>(implicit_cast<const void*>(addr));
}
struct sockaddr* sockaddr_cast(struct sockaddr_in* addr){
	return static_cast<struct sockaddr*>(implicit_cast<void*>(addr));
}
struct sockaddr_in* sockaddr_in_cast(struct sockaddr* addr){
	return static_cast<struct sockaddr_in*>(implicit_cast<void*>(addr));
}

3) 设置套接字的FD_CLOEXEC标识和O_NOBLOCK标识

FD_CLOEXEC是为了在使用execl执行的程序里,此描述符被关闭,不能再使用它,但是在使用fork调用的子进程中,此描述符并不关闭,仍可使用。

O_NOBLOCK设置套接字为非阻塞模式,经常在ET模式下使用。

void setnbAndcoeHel(int socketfd){
	int flags = ::fcntl(socketfd,F_GETFL,0);
	flags |= O_NONBLOCK;
	int res = ::fcntl(socketfd,F_SETFL,flags);
	flags = ::fcntl(socketfd,F_GETFL,0);
	flags |= FD_CLOEXEC;
	res = ::fcntl(socketfd,F_SETFL,flags);

	(void)res;
}

4) socket的创建和使用

int createNonblockingHel(int port){
	port = ((port <= 1024) || (port >= 65535)) ? 6666:port;
	
	//创建套接字
	int socketfd = ::socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK ,0);
	if(socketfd<0){
		printf("SocketsHel::createNonblockingHel:%s\n",strerror(errno));
	}
	
	return socketfd;
}

void bindHel(int socketFd,const sockaddr* addr){
	if((::bind(socketFd,addr,static_cast<socklen_t>(sizeof(sockaddr_in))))==-1){
		printf("SocketsHel::createNonblockingHel fd=%d bind:%s\n",socketFd,strerror(errno));
	}

}

void listenHel(int socketfd){
	int res = ::listen(socketfd,1024);
	if(res < 0){
		printf("SocketsHel::istenHel:%s\n",strerror(errno));
	}
	printf("成功监听%d\n",socketfd);
}

int acceptHel(int socketfd,struct sockaddr_in* addr){
	socklen_t addlen = static_cast<socklen_t>(sizeof *addr);
	int accfd = ::accept(socketfd,sockaddr_cast(addr),&addlen);
	setnbAndcoeHel(accfd);
	if(accfd < 0){
		//int savedErrno = errno;
		printf("SocketsHel::acceptHel:%s\n",strerror(errno));
	}
	return accfd;
}

5) 请求连接,读取,写入,关闭操作

int connectHel(int socketfd,const struct sockaddr* addr){
	return ::connect(socketfd,addr,static_cast<socklen_t>(sizeof(struct sockaddr_in)));
}

ssize_t readHel(int socketfd,void *buf,int count){
	return ::read(socketfd,buf,count);
}

ssize_t readvHel(int socketfd,const struct iovec *iov,int iovcnt){
		return ::readv(socketfd,iov,iovcnt);
}

ssize_t writeHel(int socketfd,const void *buf,size_t count){
	return ::write(socketfd,buf,count);
}

void closeHel(int socketfd){
	int res = ::close(socketfd);
	if(res < 0){
		printf("SocketsHel::closeHel:%s\n",strerror(errno));
	}
}

void closeWriteHel(int socketfd){
	int res = ::shutdown(socketfd,SHUT_WR);
	if(res < 0){
		printf("SocketsHel::closeWrite:%s\n",strerror(errno));
	}
}

6) sockaddr_in 和char*以及uint16_t之间的转化

void ipport_stctos(char *buf,size_t size,const struct sockaddr* addr){
	//ip_stctos(buf,size,addr);
	size_t cur = ::strlen(buf);
	const struct sockaddr_in* addr4 = sockaddr_in_cast(addr);
	uint16_t port = be16toh(addr4->sin_port);
	assert(size > cur);
	snprintf(buf+cur,size-cur,":%u",port);
}

void ip_stctos(char *buf,size_t size,const struct sockaddr* addr){
	if(addr->sa_family == AF_INET){
		assert(size >= INET_ADDRSTRLEN);
		const struct sockaddr_in* addr4 = sockaddr_in_cast(addr);
		::inet_ntop(AF_INET,&addr4->sin_addr,buf,static_cast<socklen_t>(size));
	}else if(addr->sa_family == AF_INET6){
		printf("ip_stctos receives ip6\n");
	}
}

void ipport_stostc(const char* ip,uint16_t port,struct sockaddr_in* addr){
	addr->sin_family = AF_INET;
	addr->sin_port = ::htons(port);
	if(ip == "0.0.0.0" || ip=="127.0.0.1"){
		addr->sin_addr.s_addr = ::htonl(INADDR_ANY);
		
	}else{
		if(::inet_pton(AF_INET,ip,&addr->sin_addr.s_addr) <= 0){
			printf("ipport_stostc\n");
		}

	}

}

7) 获取套接字的错误代码

int getSocketError(int socketfd){
	int optval;
	socklen_t optlen = static_cast<socklen_t>(sizeof optval);
	if(::getsockopt(socketfd,SOL_SOCKET,SO_ERROR,&optval,&optlen) < 0){
		return errno;
	}else{
		return optval;
	}
}

8) 获得本地以及对端的sockaddr_in

struct sockaddr_in getLocalAddr(int socketfd){
	struct sockaddr_in localaddr;
	memZero(&localaddr,sizeof localaddr);
	socklen_t addrlen = static_cast<socklen_t>(sizeof localaddr);
	if(::getsockname(socketfd,sockaddr_cast(&localaddr),&addrlen) < 0){
		printf("SocketsHel::getLocalAddr:%s\n",strerror(errno));
	}

	return localaddr;

}

struct sockaddr_in getPeerAddr(int socketfd){
	struct sockaddr_in peeraddr;
	memZero(&peeraddr,sizeof peeraddr);
	socklen_t addrlen = static_cast<socklen_t>(sizeof peeraddr);
	if(::getpeername(socketfd,sockaddr_cast(&peeraddr),&addrlen) < 0){
		printf("SocketsHel::getPeerAddr:%s\n",strerror(errno));
	}
	return peeraddr;
}

9) 是否发生了自连接

bool isSelfConnect(int socketfd){
	struct sockaddr_in localaddr = getLocalAddr(socketfd);
	struct sockaddr_in peeraddr = getPeerAddr(socketfd);
	if(localaddr.sin_family == AF_INET){
		const struct sockaddr_in* laddr4 = reinterpret_cast<struct sockaddr_in*>(&localaddr);
		const struct sockaddr_in* paddr4 = reinterpret_cast<struct sockaddr_in*>(&peeraddr);
		return laddr4->sin_port == paddr4->sin_port && laddr4->sin_addr.s_addr == paddr4->sin_addr.s_addr;
	}
	return false;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值