Linux下使用bind,epoll对网络编程封装
body, table{font-family: 微软雅黑; font-size: 13.5pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}
InetAddress.h | InetAddress.cpp |
#ifndef __INETADDRESS_H__
#define __INETADDRESS_H__
#include<iostream>
#include<netinet/in.h>
using namespace std;
namespace meihao
{
class InetAddress
{
public:
InetAddress(unsigned short port);
InetAddress(const string& ip,unsigned short port);
InetAddress(struct sockaddr_in addr);
const struct sockaddr_in* getInetAddressPtr();
string ip()const;
unsigned short port()const;
private:
struct sockaddr_in _addr;
};
};
#endif
|
#include"InetAddress.h"
#include<iostream>
#include<strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
namespace meihao
{
InetAddress::InetAddress(unsigned short port)
{
bzero(&_addr,sizeof(_addr));
_addr.sin_family = AF_INET;
_addr.sin_port = htons(port);
_addr.sin_addr.s_addr = INADDR_ANY;
}
InetAddress::InetAddress(const string& ip,unsigned short port)
{
bzero(&_addr,sizeof(_addr));
_addr.sin_family = AF_INET;
_addr.sin_port = htons(port);
_addr.sin_addr.s_addr = inet_addr(ip.c_str());
}
InetAddress::InetAddress(struct sockaddr_in addr)
{
_addr = addr;
}
const struct sockaddr_in* InetAddress::getInetAddressPtr()
{
return &_addr;
}
string InetAddress::ip()const
{
return string( inet_ntoa(_addr.sin_addr) );
}
unsigned short InetAddress::port()const
{
return ntohs(_addr.sin_port);
}
};
|
Socket.h | Socket.cpp |
#ifndef __SOCKET_H__
#define __SOCKET_H__
#include<iostream>
#include"InetAddress.h"
using namespace std;
namespace meihao
{
class Socket
{
public:
Socket();
Socket(int fd);
void ready(const InetAddress& addr);
int accept();
void shutdownWrite();
int fd();
static InetAddress getLocalAddress(int fd);
static InetAddress getPeerAddress(int fd);
private:
void setReuseAddr(bool on);
void setReusePort(bool on);
void bind(const InetAddress& addr);
void listen();
private:
int _fd;
};
};
#endif
|
#include"Socket.h"
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<strings.h>
using namespace std;
#define handle_error(msg) \
do{\
perror(msg);\
exit(-1);\
}while(0);
namespace meihao
{
int getSocketfd()
{
int sfd = socket(AF_INET,SOCK_STREAM,0);
if(-1==sfd)
{
handle_error("socket");
}
}
Socket::Socket():_fd(getSocketfd())
{
}
Socket::Socket(int fd):_fd(fd)
{
}
void Socket::setReuseAddr(bool on)
{
int val = on?1:0;
int ret = setsockopt(_fd,SOL_SOCKET,SO_REUSEADDR,(const void*)&val,sizeof(int));
if(-1==ret)
{
handle_error("setsockopt");
}
}
void Socket::setReusePort(bool on)
{
int val = on?1:0;
int ret = setsockopt(_fd,SOL_SOCKET,SO_REUSEPORT,(const void *)&val,sizeof(int));
if(-1==ret)
{
handle_error("setsockopt");
}
}
void Socket::bind(const InetAddress& addr)
{
int ret = ::bind(_fd,(const struct sockaddr*)&addr,(socklen_t)sizeof(addr));
if(-1==ret)
{
handle_error("::bind");
}
}
void Socket::listen()
{
int ret = ::listen(_fd,10);
if(-1==ret)
{
handle_error("::listen");
}
}
void Socket::ready(const InetAddress& addr)
{
setReuseAddr(true);
setReusePort(true);
bind(addr);
listen();
}
int Socket::accept()
{
int new_fd = ::accept(_fd,NULL,NULL);
if(-1==new_fd)
{
handle_error("::accept");
}
}
void Socket::shutdownWrite()
{
int ret = ::shutdown(_fd,SHUT_WR);
if(-1==ret)
{
handle_error("::shutdown");
}
}
int Socket::fd()
{
return _fd;
}
InetAddress Socket::getLocalAddress(int fd)
{
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));
int addrlen = sizeof(addr);
int ret = ::getsockname(fd,(struct sockaddr*)&addr,(socklen_t*)&addrlen);
if(-1==ret)
{
handle_error("::getsockname");
}
return InetAddress(addr);
}
InetAddress Socket::getPeerAddress(int fd)
{
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));
int addrlen = sizeof(addr);
int ret = ::getpeername(fd,(struct sockaddr*)&addr,(socklen_t*)&addrlen);
if(-1==ret)
{
handle_error("::getpeername");
}
return InetAddress(addr);
}
};
|
SocketIO.h | SocketIO.cpp |
#ifndef __SOCKETIO_H__
#define __SOCKETIO_H__
#include<iostream>
using namespace std;
namespace meihao
{
class SocketIO
{
public:
SocketIO(int fd);
int readn(char* buf,int count);
int writen(const char* buf,int count);
int readline(char* buf,int maxlen); // 成功返回读取字节数,失败返回-1
private:
int recvPeek(char* buf,int count); // 预读取一行
private:
int _fd;
};
};
#endif
|
#include"SocketIO.h"
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
namespace meihao
{
SocketIO::SocketIO(int fd):_fd(fd)
{
}
int SocketIO::readn(char* buf,int count)
{
int left = count;
char* ptmp = buf;
while(left>0)
{
int nread = ::recv(_fd,ptmp,left,0);
if(-1==nread)
{
if(errno==EINTR)
continue;
exit(EXIT_FAILURE);
}
else if(0==nread)
break;
left -= nread;
ptmp += nread;
}
return count-left; // 返回发送的数据个数
}
int SocketIO::writen(const char* buf,int count)
{
int left = count;
const char* ptmp = buf;
while(left>0)
{
int nread = ::send(_fd,ptmp,left,0);
if(-1==nread)
{
if(errno==EINTR)
continue;
exit(EXIT_FAILURE);
}
else if(0==nread)
break;
left -= nread;
ptmp += nread;
}
return count-left;
}
int SocketIO::recvPeek(char* buf,int count)
{
int nread = ::recv(_fd,buf,count,MSG_PEEK);
if(-1==nread)
{
perror("recvPeek");
}
}
int SocketIO::readline(char* buf,int maxlen) // 失败返回-1
{
int left = maxlen;
char* ptmp = buf;
int nread = 0;
while(left>0)
{
nread = recvPeek(ptmp,left);
if(-1==nread)
{
if(errno==EINTR)
continue;
return -1;
}
else if(0==nread)
return -1;
for(int idx=0;idx<nread;idx++)
{
if(ptmp[idx]=='\n')
{
if(readn(ptmp,nread)!=nread)
return -1;
left -= nread;
return maxlen-left;
}
}
// 预读取一行没有读到换行
if(readn(ptmp,nread)!=nread)
return -1;
ptmp += nread;
left -= nread;
}
return maxlen-left;
}
};
|
TcpConnection.h | TcpConnection.cpp |
#ifndef __TCPCONNECTION_H__
#define __TCPCONNECTION_H__
#include<iostream>
#include"SocketIO.h"
#include"Socket.h"
#include"InetAddress.h"
#include<memory>
using namespace std;
namespace meihao
{
class TcpConnection;
typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;
//利用智能共享指针托管TcpConnection类型指针,这样不用考虑最后的资源释放
typedef function<void(const TcpConnectionPtr& conn)> TcpConnectionCallback; // 这里要为public,不然后面的Epoll类访问不到,最开始我放到类里面了,放到外面访问更方便
//function函数对象绑定回调函数
class TcpConnection:public std::enable_shared_from_this<TcpConnection>
{
//继承enable_shared_from_this,使用里面的shared_from_this()方法传递指向函数
//本身的指针,防止出现shared_ptr误用造成多次释放或者拷贝
public:
TcpConnection(int confd); // 连接到的fd
~TcpConnection();
string receive();
void send(const string& msg);
void shutdown();
string toString(); // 输出服务器端信息和连接上的客户端的信息
void setConnectionCallback(TcpConnectionCallback cb);
void setMessageCallback(TcpConnectionCallback cb);
void setCloseCallback(TcpConnectionCallback cb);
void handleConnectionCallback(); // 客户端连接上后做出的操作
void handleMessageCallback(); // 服务器端-客户端之间发送消息
void handleCloseCallback(); // 服务器端关闭连接做出的行为
private:
Socket _sock;
SocketIO _sockIO;
InetAddress _localAddress;
InetAddress _peerAddress;
bool _isShutdownWrite;
TcpConnectionCallback _onConnectionCb; // 请求连接到服务器做出的行为
TcpConnectionCallback _onMessageCb; // 双方发送消息
TcpConnectionCallback _onCloseCb; // 关闭链接行为
};
};
#endif
|
#include"TcpConnection.h"
#include<iostream>
#include<strings.h>
#include<stdlib.h>
#include<sstream>
#include<errno.h>
#define handle_error(msg) \
do{\
perror(msg);\
exit(-1);\
}while(0);
using namespace std;
namespace meihao
{
TcpConnection::TcpConnection(int confd):_sock(confd)
,_sockIO(confd)
,_localAddress(meihao::Socket::getLocalAddress(confd))
,_peerAddress(meihao::Socket::getPeerAddress(confd))
,_isShutdownWrite(false)
{
//剩下的回调函数使用成员函数来设置,方便使用过程中修改
}
TcpConnection::~TcpConnection()
{
}
string TcpConnection::receive()
{
char buf[1024];
bzero(buf,sizeof(buf));
int ret = _sockIO.readline(buf,sizeof(buf));
if(-1==ret)
{
handle_error("recvive");
}
return string(buf);
}
void TcpConnection::send(const string& msg)
{
_sockIO.writen(msg.c_str(),msg.size());
}
void TcpConnection::shutdown()
{
if(!_isShutdownWrite) // 没有关闭
{
_isShutdownWrite = true;
_sock.shutdownWrite();
}
}
string TcpConnection::toString()
{
ostringstream oss;
oss<<_localAddress.ip()<<" "<<_localAddress.port()<<"--->"
<<_peerAddress.ip()<<" "<<_peerAddress.port()<<endl;
return oss.str();
}
// 开始初始化类里面的回调函数的值
void TcpConnection::setConnectionCallback(TcpConnectionCallback cb)
{
_onConnectionCb = cb;
}
void TcpConnection::setMessageCallback(TcpConnectionCallback cb)
{
_onMessageCb = cb;
}
void TcpConnection::setCloseCallback(TcpConnectionCallback cb)
{
_onCloseCb = cb;
}
void TcpConnection::handleConnectionCallback()
{
if(_onConnectionCb)
{
_onConnectionCb(shared_from_this()); // 传调用该函数的指针本身
// 等价于 shared_ptr<TcpConnection>(this);
}
}
void TcpConnection::handleMessageCallback()
{
if(_onMessageCb)
{
_onMessageCb(shared_from_this());
}
}
void TcpConnection::handleCloseCallback()
{
if(_onCloseCb)
{
_onCloseCb(shared_from_this());
}
}
};
|
Epoll.h | Epoll.cpp |
#ifndef __EPOLL_H__
#define __EPOLL_H__
#include<iostream>
#include"TcpConnection.h"
#include<vector>
#include<sys/epoll.h>
#include<map>
using namespace std;
namespace meihao
{
class Epoll
{
public:
Epoll(int sfd);
void loop();
void unloop();
void waitEpollfd();
//在epoll类中用函数设置TcpConnection类中的私有变量
void epollSetConnectionCallback(TcpConnectionCallback cb);
void epollSetMessageCallback(TcpConnectionCallback cb);
void epollSetCloseCallback(TcpConnectionCallback cb);
private:
void handleConnection(); //epoll处理新连接的客户端
void handleMessage(int connfd); //处理消息
bool isConnected(int connfd); //查看描述符是否断开
private:
int _efd; // epoll_create得到的fd
int _sfd; // sockfd,用来监听客户端请求
bool _isLooping; // 是否还在监听客户端请求
vector<struct epoll_event> _events; //存放epoll_wait返回的监听描述符事件数组
map<int,TcpConnectionPtr> _mapConnections; // 存放所有客户端请求的描述符和对应的智能指针
TcpConnectionCallback _onConnectionCb; // 为监听到的客户端设置连接的回调函数
TcpConnectionCallback _onMessageCb;
TcpConnectionCallback _onCloseCb;
};
};
#endif
|
#include"Epoll.h"
#include<iostream>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/epoll.h>
using namespace std;
#define handle_error(msg)\
do{\
perror(msg);\
exit(EXIT_FAILURE);\
}while(0);
namespace meihao
{
int createEpollfd()
{
int efd = ::epoll_create(1); //参数不为0即可
if(-1==efd)
{
handle_error("epoll_create");
}
return efd;
}
void addEpollfd(int efd,int fd)
{
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = fd;
int ret = epoll_ctl(efd,EPOLL_CTL_ADD,fd,&event);
if(-1==ret)
{
handle_error("epoll_ctl");
}
}
void delEpollfd(int efd,int fd)
{
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = fd;
int ret = epoll_ctl(efd,EPOLL_CTL_DEL,fd,&event);
if(-1==ret)
{
handle_error("epoll_ctl_del");
}
}
Epoll::Epoll(int sfd):_efd(createEpollfd())
,_sfd(sfd)
,_isLooping(false)
,_events(1024) // 容器提前开辟空间
{
addEpollfd(_efd,_sfd);
}
void Epoll::loop() // 开启监听客户端连接请求
{
_isLooping = true;
while(_isLooping)
{
waitEpollfd();
}
}
void Epoll::unloop() //关闭epoll监听
{
if(_isLooping)
_isLooping = false;
}
void Epoll::waitEpollfd()
{
int ret;
do
{
ret = ::epoll_wait(_efd,&(*_events.begin()),_events.size(),5000);
// 事件满足的fd会放到vector里面
}while(-1==ret&&errno==EINTR); // 被中断打断
if(-1==ret)
{
handle_error("epoll_wait");
}
else if(0==ret) // 5S后超时返回
{
cout<<"Epoll wait timeout!"<<endl;
}
for(int idx=0;idx!=ret;++idx)
{
if(_events[idx].data.fd ==_sfd &&_events[idx].events == EPOLLIN)
{//处理新连接
handleConnection();
}
else if(_events[idx].events == EPOLLIN)
{//处理已经连接上的客户端的输入请求
handleMessage(_events[idx].data.fd);
}
}
}
void Epoll::handleConnection()
{
int connfd = ::accept(_sfd,NULL,NULL);
addEpollfd(_efd,connfd);
//处理新的TCP链接
TcpConnectionPtr con(new TcpConnection(connfd));
cout<<"TcpConnectionPtr"<<con<<endl;
//设置TcpConnectionPtr的回调函数
con->setConnectionCallback(_onConnectionCb);
con->setMessageCallback(_onMessageCb);
con->setCloseCallback(_onCloseCb);
_mapConnections.insert(::make_pair(connfd,con)); //map中插入新连接的请求
con->handleConnectionCallback();
}
void Epoll::handleMessage(int connfd)
{
auto it = _mapConnections.find(connfd); //找到map中存放的对应描述符的关键字
if(it!=_mapConnections.end()) //如果描述符确实存在
{
bool flag = isConnected(connfd);
if(flag)
{//链接没有断开
it->second->handleMessageCallback(); //tcp连接处理消息,调用的是TcpConnection类里的函数
}
else
{//断开
delEpollfd(_efd,connfd);
it->second->handleCloseCallback(); //打印显示断开信息
_mapConnections.erase(it); //map中删除对应的pair
}
}
}
bool Epoll::isConnected(int connfd)
{
int ret;
char buf[512];
do
{
ret = recv(connfd,buf,sizeof(buf),MSG_PEEK); //从内核缓冲区预读取
}while(-1==ret&&errno==EINTR);
return ret>0; //>0表示有数据可读,链接没有断开
}
void Epoll::epollSetConnectionCallback(TcpConnectionCallback cb)
{
_onConnectionCb = cb;
}
void Epoll::epollSetMessageCallback(TcpConnectionCallback cb)
{
_onMessageCb = cb;
}
void Epoll::epollSetCloseCallback(TcpConnectionCallback cb)
{
_onCloseCb = cb;
}
};
|
TcpServer.h | TcpServer.cpp |
#ifndef __TCPSERVER_H__
#define __TCPSERVER_H__
#include<iostream>
#include"InetAddress.h"
#include"Socket.h"
#include"Epoll.h"
#include"TcpConnection.h"
using namespace std;
namespace meihao
{
class TcpServer
{
public:
TcpServer(unsigned short port);
TcpServer(const string& ip,unsigned short port);
TcpServer(const InetAddress& addr);
void start();
void stop();
void tcpServerSetConnectionCallback(TcpConnectionCallback cb);
void tcpServerSetMessageCallback(TcpConnectionCallback cb);
void tcpServerSetCloseCallback(TcpConnectionCallback cb);
private:
InetAddress _addr;
Socket _serverSock;
Epoll _epoll;
TcpConnectionCallback _onConnectionCb;
TcpConnectionCallback _onMessageCb;
TcpConnectionCallback _onCloseCb;
};
};
#endif
|
#include"TcpServer.h"
#include<iostream>
using namespace std;
namespace meihao
{
TcpServer::TcpServer(unsigned short port):_addr(port)
,_serverSock()
,_epoll(_serverSock.fd())
{
}
TcpServer::TcpServer(const string& ip,unsigned short port):_addr(ip,port)
,_serverSock()
,_epoll(_serverSock.fd())
{
}
TcpServer::TcpServer(const InetAddress& addr):_addr(addr)
,_serverSock()
,_epoll(_serverSock.fd())
{
}
void TcpServer::start()
{
_serverSock.ready(_addr); // 开启服务器,并监听
//epoll类设置请求的tcp连接的回调函数
_epoll.epollSetConnectionCallback(_onConnectionCb);
_epoll.epollSetMessageCallback(_onMessageCb);
_epoll.epollSetCloseCallback(_onCloseCb);
_epoll.loop(); // epoll_wait客户端连接请求
}
void TcpServer::stop()
{
_epoll.unloop();
_serverSock.shutdownWrite();
}
void TcpServer::tcpServerSetConnectionCallback(TcpConnectionCallback cb)
{
_onConnectionCb = cb;
}
void TcpServer::tcpServerSetMessageCallback(TcpConnectionCallback cb)
{
_onMessageCb = cb;
}
void TcpServer::tcpServerSetCloseCallback(TcpConnectionCallback cb)
{
_onCloseCb = cb;
}
};
|
server.cpp | Makefile |
#include<iostream>
#include"TcpServer.h"
#include"TcpConnection.h"
using namespace std;
void onConnection(const meihao::TcpConnectionPtr& conn)
{
cout<<conn->toString()<<"has connected!"<<endl;
conn->send("connect success!\n");
}
void onMessage(const meihao::TcpConnectionPtr& conn)
{
string msg = conn->receive();
cout<<"recv:"<<msg;
conn->send(msg);
}
void onClosed(const meihao::TcpConnectionPtr& conn)
{
cout<<conn->toString()<<"has closed!"<<endl;
}
int main()
{
meihao::TcpServer tcpServer(8848);
tcpServer.tcpServerSetConnectionCallback(onConnection);
tcpServer.tcpServerSetMessageCallback(onMessage);
tcpServer.tcpServerSetCloseCallback(onClosed);
tcpServer.start();
}
|
OBJS:=*.cpp
ELF:=server
$(ELF):$(OBJS)
g++ $(OBJS) -o $(ELF) -std=c++11
.PHONY:rebuild clean
rebuild:
make clean $(ELF)
clean:
rm -rf $(ELF)
|
client.cpp |
#include<iostream>
#include"InetAddress.h"
#include"SocketIO.h"
#include<strings.h>
#include<unistd.h>
using namespace std;
int main()
{
meihao::InetAddress inetAddr(8848);
int sfd = socket(AF_INET,SOCK_STREAM,0);
if(-1==sfd)
{
perror("socket");
exit(EXIT_FAILURE);
}
int ret = connect(sfd,(const struct sockaddr*)inetAddr.getInetAddressPtr(),sizeof(struct sockaddr));
if(-1==ret)
{
perror("connect");
exit(EXIT_FAILURE);
}
meihao::SocketIO socketIO(sfd);
char buf[1024] = "";
socketIO.readline(buf,sizeof(buf));
cout<<buf;
while(1)
{
bzero(buf,sizeof(buf));
read(0,buf,sizeof(buf));
socketIO.writen(buf,sizeof(buf));
bzero(buf,sizeof(buf));
socketIO.readline(buf,sizeof(buf));
cout<<"recv from server:"<<buf;
}
}
|
Linux下使用bind,epoll对网络编程封装的更多相关文章
- Linux下C语言的socket网络编程
关于详细的服务器建立的步骤以及相关的socket套接字的知识我已经在python socket编程的文章中提到过了,大家可以参看那一篇博客来历接socket套接字编程的内容,由于要是用C相关的API所 ...
- 使用c语言实现在linux下的openssl客户端和服务器端编程
使用c语言实现在linux下的openssl客户端和服务器端编程 摘自:https://www.cnblogs.com/etangyushan/p/3679457.html 前几天组长让我实现一个使用 ...
- linux下select/poll/epoll机制的比较
select.poll.epoll简介 epoll跟select都能提供多路I/O复用的解决方案.在现在的Linux内核里有都能够支持,其中epoll是Linux所特有,而select则应该是POSI ...
- linux下ACE使用epoll
select和epoll的比较就不用多说了.ACE在linux下默认使用select来实现Reactor的.如何在linux下让ACE使用epoll. 1.加一个编译宏,告诉ACE不要使用默认的sel ...
- linux下测试web访问及网络相关的命令
curl命令 curl是linux系统命令行下用来简单测试web访问的工具. curl -xip:port www.baidu.com -x可以指定ip和端口,省略写hosts,方便实用 -I ...
- linux下select,poll,epoll的使用与重点分析
好久没用I/O复用了,感觉差点儿相同都快忘完了.记得当初刚学I/O复用的时候花了好多时间.可是因为那会不太爱写博客,导致花非常多时间搞明确的东西,依旧非常easy忘记.俗话说眼过千遍不如手过一遍,的确 ...
- Linux下C与Mysql的混合编程(转)
1 概述 MySQL 是一个关系型数据库管理系统.由瑞典MySQL AB公司开发,眼下属于Oracle公司.MySQL是最流行的关系型数据库管理系统. 支持AIX.FreeBSD.HP-UX.Linu ...
- Linux下管道重定向使用以及Shell编程(操作系统)
实验名称:Linux的基本操作 实验目的: 1.了解管道和重定向 2.熟悉基本的Linux脚本的编写 实验环境:Ubuntu 12.4(32位,简体中文) 实验内容: 1.将当前用户目录下的文件清单输 ...
- Linux下C与Mysql的混合编程
1 概述 MySQL 是一个关系型数据库管理系统.由瑞典MySQL AB公司开发,眼下属于Oracle公司.MySQL是最流行的关系型数据库管理系统. 支持AIX.FreeBSD.HP-UX.Linu ...
随机推荐
- Codeforces Gym - 101102A - Coins
A. Coins 题目链接:http://codeforces.com/gym/101102/problem/A time limit per test 3 seconds memory limit ...
- git Bash下复制粘贴
git复制:Ctrl+insert git粘贴:Shift+Insert git常用快捷键链接地址:https://www.jianshu.com/p/cc1fbd89e087 在gitHup上下载他 ...
- [C#]获取连接MySql数据库及常用的CRUD操作
测试如下: 首先添加引用:MySql.Data.dll 链接:http://pan.baidu.com/s/1dEQgLpf 密码:bnyu *将链接数据库的信息放入配置文件中(app.config) ...
- ajax和iframe区别
ajax和iframe https://segmentfault.com/a/1190000011967786 ajax和iframe的区别 1.都是局部刷新 2.iframe是同步的,而ajax是异 ...
- Lua --- 输入一个数字,输出阶乘
function fact(n) == n then else ) end end print("Enter a number : ") a = io.read("*nu ...
- MySql常用函数 --MySql
1.目标 MySQL数据库中提供了很丰富的函数.MySQL函数包括数学函数.字符串函数.日期和时间函数.条件判断函数.系统信息函数.加密函数.格式化函数等.通过这些函数,可以简化用户的操作.例如,字符 ...
- WPF触发器(Trigger)
WPF触发器(Trigger.DataTrigger.EventTrigger) WPF中有种叫做触发器的东西(记住不是数据库的trigger哦).它的主要作用是根据trigger的不同条件来自动更改 ...
- Spring Boot之实现自动配置
GITHUB地址:https://github.com/zhangboqing/springboot-learning 一.Spring Boot自动配置原理 自动配置功能是由@SpringBootA ...
- PHP单例模式实例,连接数据库对类的引用
<?php//单例模式连接数据库class pzhang{ static private $instance; private static $config; private $dbase = ...
- 使用xshell远程连接
xshell 是一个强大的安全终端模拟软件,它支持SSH1,SSH2以及microsoft windows 平台的TELNET协议.xshell通过互联网到远程主机的安全连接. xshell可以在wi ...