写一个服务器程序
写一个简单的服务器,客户端链接服务器之后,服务器给其发一个Hello World之后,中断服务器和客户端的链接。
写c++的时候,尤其是服务器开发会对异常情况作处理。
int main_codeblock_if() {
...
int ret = listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == ret)
{
log(socket());
close(listenfd);
exit(-100);
}
...
//socket 2
ret = bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if(-1 == ret)
{
log(bind());
close(listenfd);
exit(-100);
}
...
//socket 3
ret = listen(listenfd, 20);
if(-1 == ret)
{
log(listen());
close(listenfd);
exit(-100);
}
...
}
常见的场景还比如:
void codeBlock1()
{
char *string = new char[1024];
if(condition1)
{
delete [] string;
string = nullptr;
}
if(condition2)
{
delete [] string;
string = nullptr;
}
if(condition3)
{
delete [] string;
string = nullptr;
}
delete [] string;
string = nullptr;
}
可以概括为:先分配资源,在进行相关操作,在中间步骤中出错,对相应的资源进行回收。
在资源回收很容易忘掉,或者没有执行到其中(逻辑分支不能达到,抛出异常),造成内存泄漏。有没有方法避免这种情况?C++ RAII机制可以供我们使用。
RAII 防止内存泄漏
RAII即资源获取就是初始化,我们拿到资源的时候直接使用就可以了,跳过初始化,析构(资源回收)的步骤。原理上是使用栈内变量离开自己的作用域之后,自动释放掉资源的性质。
一开始我不知怎么设计这个类,看了书上封装之后的用法,明白了。
{
Socket_RAII socket;
if(false == socket.init()) return -1;
if(false == socket.bind()) return -1;
if(false == socket.listen()) return -1;
soket.work();
}
//离开 之后sobket 自动被释放掉
服务器代码
int main()
{
{
socket_RAII socket;
if(false == socket.socket_init())
{
return -1;
}
if(false == socket.socket_bind("127.0.0.1",2333))
{
return -1;
}
if(false == socket.socket_listen(20))
{
return -1;
}
socket.work();
}
}
class socket_RAII {
public:
bool socket_init()
{
memset(&serveraddr,0,sizeof (serveraddr));
m_listenfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == m_listenfd)
{
// logger
// assert(-1 != m_listenfd);
return false;
}
return true;
}
bool socket_bind(string ip,int port) {
in_addr addr;
int res = inet_aton(ip.c_str(),&addr);
if(0 == res)
{
// log ip convert error
return false;
}
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(port);
socklen_t len = sizeof(serveraddr);
int ret = bind(m_listenfd, (struct sockaddr *) &serveraddr,len );
if(-1 == ret)
{
return false;
}
return true;
}
bool socket_listen(int value)
{
int ret = listen(m_listenfd, value);
if(-1 == ret)
{
return false;
}
return true;
}
void work()
{
do {
sockaddr_in cliaddr;
memset(&cliaddr,0,sizeof (cliaddr));
socklen_t cliaddr_len = sizeof(cliaddr);
int connfd = accept(m_listenfd, (sockaddr *) &cliaddr, &cliaddr_len);
assert (-1 != connfd);
printf("connfd: %d Client IP: %s Port %d \n", connfd, inet_ntoa(cliaddr.sin_addr),
ntohs(cliaddr.sin_port));
//async_do_work_struct(connfd);
sync_do_work(connfd);
} while(0);
}
private:
void sync_do_work(int fd) {
char writeBuffer[1024] = {'\0'};
std::sprintf(writeBuffer, "%s", "hello world \n");
int byteNum = send(fd, writeBuffer, strlen(writeBuffer), 0);
close(fd);
}
public:
socket_RAII()
{
m_listenfd = -1;
}
~socket_RAII()
{
if(-1 != m_listenfd ) close(m_listenfd);
cout << "~socket_RAII()" << endl;
}
private:
int m_listenfd;
sockaddr_in serveraddr;
};
客户端代码
int main() {
in_addr addr;
int res = inet_aton("192.168.1.1",&addr);
//socket 1
int clientfd = 0;
int ret = clientfd = socket(AF_INET, SOCK_STREAM, 0);
assert(-1 != ret);
struct sockaddr_in servaddr, cliaddr;
int port = 2333;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
socklen_t seraddr_len = sizeof(servaddr);
ret = connect(clientfd,(sockaddr *) &servaddr,seraddr_len);
while(1)
{
char readBuffer[1024] = {'\0'};
int bytenum = recv(clientfd,readBuffer,sizeof (readBuffer),0);
if(0 == bytenum)
{
printf("%s","client shut down.\n");
break;
}
printf("%s",readBuffer);
}
close(clientfd);
return 0;
}