最近在看服务器框架的搭建,看了不少,都是零零碎碎的,觉得看的差不多了,可以写点最后的总结了,然后,竟然发现了这篇文章,总结做的特别好,肯定比我总结写要好多了,所以我也就不写了,直接转吧。。。。。。

套接字模式:锁定、非锁定
套接字I/O模型:       select(选择)
WSAAsyncSelect(异步选择)
WSAEventSelect(事件选择)
Overlapped I/O(重叠式I / O)
Completion port(完成端口)


一、 简介

套接字模型的出现,是为了解决套接字模式存在的某些限制。
所有Wi n d o w s平台都支持套接字以锁定或非锁定方式工作。然而,并非每种平台都支持每一种I / O模型。
操作系统对套接字I / O模型的支持情况

平台
select
WSAAsync
WSAEventSelect
Overlapped
Completion Port
Windows CE
支持
不支持
不支持
不支持
不支持
Windows 95(Winsock 1)
支持
支持
不支持
不支持
不支持
Windows 95(Winsock 2)
支持
支持
支持
支持
不支持
Windows 98
支持
支持
支持
支持
不支持
Windows NT
支持
支持
支持
支持
支持
Windows 2000
支持
支持
支持
支持
支持

二、          套接字模式

在锁定模式下,在I / O操作完成前,执行操作的Winsock函数(比如send和recv)会一直等候下去,不会立即返回程序(将控制权交还给程序)。而在非锁定模式下,Winsock函数无论如何都会立即返回。

锁定模式
处在锁定模式的套接字,因为在一个锁定套接字上调用任何一个Winsock API函数,都会产生相同的后果—耗费或长或短的时间"等待"。

非锁定模式
SOCKET s;
unsigned long ul=1;
int nRet;
s = socket(AF_INET,SOCK_STREAM,0);
nRet = ioctlsocket(s,FIOBIO,(unsigned long *) &ul);
if(nRet == SOCKET_ERROR)
{
      //Failed to put the socket into nonblocking mode
}

三、  套接字I/O模型

1. select模型
select函数,可以判断套接字上是否存在数据,或者能否向一个套接字写入数据。
处于锁定模式时,防止I / O调用(如send或recv),进入"锁定"状态;同时防止在套处于非锁定模式时,防止产生WSAEWOULDBLOCK错误。
除非满足事先用参数规定的条件,否则select函数会在进行I / O操作时锁定。

select的函数原型:
int select(
      int nfds,//会被忽略, 为了保持与早期的B e r k e l e y套接字应用程序的兼容
fd_set FAR * readfds,//检查可读性
fd_set FAR * writefds,//检查可写性
fd_set FAR * exceptfds,//于例外数据
const struct timeval FAR * timeout//最多等待I / O操作完成多久的时间。如是空指针,无限期等
);
//fd_set数据类型代表着一系列特定套接字的集合
Wi n s o c k提供下列宏对f d _ s e t进行处理与检查:
■ FD_CLR(s, *set):从s e t中删除套接字s。
■ FD_ISSET(s, *set):检查s是否s e t集合的一名成员;如答案是肯定的是,则返回T R U E。
■ FD_SET(s, *set):将套接字s加入集合s e t。
■ F D _ Z E R O ( * s e t ):将s e t初始化成空集合。

步骤:
1) 使用F D _ Z E R O宏,初始化自己感兴趣的每一个f d _ s e t。
2) 使用F D _ S E T宏,将套接字句柄分配给自己感兴趣的每个f d _ s e t。
3) 调用s e l e c t函数,然后等待在指定的f d _ s e t集合中,I / O活动设置好一个或多个套接字句柄。s e l e c t完成后,会返回在所有f d _ s e t集合中设置的套接字句柄总数,并对每个集合进行相应的更新。
4) 根据s e l e c t的返回值,我们的应用程序便可判断出哪些套接字存在着尚未完成的I / O操作—具体的方法是使用F D _ I S S E T宏,对每个f d _ s e t集合进行检查。
5) 知道了每个集合中"待决"的I / O操作之后,对I / O进行处理,然后返回步骤1 ),继续进行s e l e c t处理。
s e l e c t返回后,它会修改每个f d _ s e t结构,删除那些不存在待决I / O操作的套接字句柄。这正是我们在上述的步骤( 4 )中,为何要使用F D _ I S S E T宏来判断一个特定的套接字是否仍在集合中的原因。
SOCKET s;
fd_set fdread;
int ret;
//create a socket, and accept a connection
//Manage I/O on the socket
while(TRUE)
{
//Always clear the read set before calling select()
FD_ZERO(&fdread);
//Add socket s to the read set
FD_SET(s,&fdread);
If((ret=select(0,&fdread,NULL,NULL,NULL))== SOCKET_ERROR){
    //Error condition
}
if(ret>0)
{
    //For this simple case, select() should return the value 1. An application dealing with
      //more than one socket could get a value greater than 1.At this point,your application
//should check to see whether the socket is part of a set.
If(FD_ISSET(s,&fdread))
{
                //A read event has occurred on socket s
}
}
}

2. WSAAsyncSelect
有用的异步I / O模型,利用这个模型,应用程序可在一个套接字上,接收以Windows消息为基础的网络事件通知。
函数原型:
int WSAAsyncSelect(
     SOCKET s,
     HWND hWnd,//收到通知消息的那个窗口
     unsigned int wMsg, //指定在发生网络事件时,打算接收的消息
     long lEvent//位掩码,对应于一系列网络事件的组合
);

用于WSAAsyncSelect函数的网络事件:
FD_READ 应用程序想要接收有关是否可读的通知,以便读入数据
FD_WRITE 应用程序想要接收有关是否可写的通知,以便写入数据
FD_OOB 应用程序想接收是否有带外(OOB)数据抵达的通知
FD_ACCEPT 应用程序想接收与进入连接有关的通知
FD_CONNECT 应用程序想接收与一次连接或者多点join操作完成的通知
FD_CLOSE 应用程序想接收与套接字关闭有关的通知
FD_QOS 应用程序想接收套接字"服务质量"(QoS)发生更改的通知
FD_GROUP_QOS 应用程序想接收套接字组"服务质量"发生更改的通知(为未来套接字组的使用保留)
FD_ROUTING_INTERFACE_CHANGE 应用程序想接收在指定的方向上,与路由接口发生变化的通知
FD_ADDRESS_LIST_CHANGE 应用程序想接收针对套接字的协议家族,本地地址列表发生变化的通知

窗口例程,函数原型:
LRESULT CALLBACK WindowProc(
     HWND hWnd,
     UINT uMsg,
     WPARAM wParam,
     LPARAM lParam
);
WSAAsyncSelect
调用中定义的消息。wParam参数指定在其上面发生了一个网络事件的套接字。假若同时为这个窗口例程分配了多个套接字,这个参数的重要性便显示出来了。
在lParam参数中,包含了两方面重要的信息。其中,
lParam的低位字指定了已经发生的网络事件,而lParam的高位字包含了可能出现的任何错误代码。
网络事件消息
抵达一个窗口例程后,应用程序首先应检查lParam的高字位,以判断是否在套接字上发生了一个网络错误。这里有一个特殊的宏:
WSAGETSELECTERROR,可用它返回高字位包含的错误信息。若应用程序发现套接字上没有产生任何错误,接着便应调查到底是哪个网络事件类型,
造成了这条Windows消息的触发—具体的做法便是读取lParam之低字位的内容。此时可使用另一个特殊的宏:WSAGETSELECTEVENT,
用它返回lParam的低字部分。

3.WSAEventSelect
异步I / O模型, 网络事件投递至一个事件对象句柄,而非投递至一个窗口例程。

1.      针对打算使用的每一个套接字,首先创建一个事件对象。
WSAEVENT WSACreateEvent(void);
*相关的函数:BOOL WSAResetEvent(WSAEVENT hEvent);BOOL WSACloseEvent(WSAEVENT hEvent);
WSACreateEvent创建的事件拥有两种工作状态:signaled和nonsignaled,以及两种工作模式:manual reset和auto reset。

2.     将其与某个套接字关联在一起,同时注册自己感兴趣的网络事件类型。
int WSAEventSelect(Socket s,WSAEVENT hEventObject,long lNetworkEvents);

3.      套
接字同一个事件对象句柄关联在一起后,应用程序便可开始I/O处理;方法是等待网络事件触发事件对象句柄的工作状态。
WSAWaitForMultipleEvents函数的设计宗旨便是用来等待一个或多个事件对象句柄,并在事先指定的一个或所有句柄进入"已传信"状态
后,或在超过了一个规定的时间周期后,立即返回。
DWORD WSAWaitForMultipleEvents(
           DWORD cEvents,
           const WSAEVENT FAR * lphEvents,
           BOOL fWaitAll,
           DWORD dwTimeOut,
           BOOL fAlertable
);
WSAWaitForMultipleEvents
只能支持由WSA_MAXIMUM_WAIT_EVENTS对象规定的一个最大值,在此定义成64个。因此,针对发出
WSAWaitForMultipleEvents调用的每个线程,该I/O模型一次最多都只能支持6
4个套接字。假如想让这个模型同时管理不止64个套接字,必须创建额外的工作者线程,以便等待更多的事件对象。

4.     知道了造成网络事件的套接字后,接下来调用WSAEnumNetworkEvents函数,调查发生了什么类型的网络事件。
int WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents);

4. Overlapped I/O
重叠I / O(Overlapped I/O)模型使应用程序能达到更佳的系统性能。
重叠模型的基本设计原理便是让应用程序使用一个重叠的数据结构,一次投递一个或多个Winsock I/O请求。

先使用WSA_FLAG_OVERLAPPED这个标志,创建一个套接字。s = WSASocket(AF_INET, SOCK_STREAM, 0

,NULL,0,WSA_FLAG_OVERLAPPED);创建套接字的时候,假如使用的是socket函数,而非WSASocket函数,那么会默认
设置WSA_FLAG_OVERLAPPED标志。成功建好一个套接字,同时将其与一个本地接口绑定到一起后,便可开始进行重叠I / O
操作,方法是调用下述的Wi n s o c k 函数,同时指定一个WSAOVERLAPPED结构(可选):
■ WSASend
■ WSASendTo
■ WSARecv
■ WSARecvFrom
■ WSAIoctl
■ AcceptEx
■ TrnasmitFile
步骤:
1) 创建一个套接字,开始在指定的端口上监听连接请求。
2) 接受一个进入的连接请求。
3) 为接受的套接字新建一个WSAOVERLAPPED结构,并为该结构分配一个事件对象句柄。也将事件对象句柄分配给一个事件数组,以便稍后由WSAWaitForMultipleEvents函数使用。
4) 在套接字上投递一个异步WSARecv请求,指定参数为WSAOVERLAPPED结构。注意函数通常会以失败告终,返回SOCKET_ERROR错误状态WSA_IO_PENDING(I/O操作尚未完成)。
5) 使用步骤3 )的事件数组,调用WSAWaitForMultipleEvents函数,并等待与重叠调用关联在一起的事件进入"已传信"状态(换言之,等待那个事件的"触发")。
6) WSAWaitForMultipleEvents函数完成后,针对事件数组,调用WSAResetEvent(重设事件)函数,从而重设事件对象,并对完成的重叠请求进行处理。
7) 使用WSAGetOverlappedResult函数,判断重叠调用的返回状态是什么。
8) 在套接字上投递另一个重叠WSARecv请求。
9) 重复步骤5 ) ~ 8 )。
                     
              void main(void)
{
      WSABUF DataBuf;
      DWORD EventTotal = 0;
      WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
      WSAOVERLAPPED AcceptOverlapped;
      SOCKET ListenSocket,AcceptSocket;
      //Step 1:Start Winsock and set up a listening socket
      ...
      //Step 2:Accept an inbound connection
      AcceptSocket = accept(ListenSocket, NULL , NULL);
      //Step 3:Set up an overlapped structure
      EventArray[EventTotal] = WSACreateEvent();
      ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
      AcceptOverlapped.hEvent= EventArray[EventTotal];          
      DataBuf.len = DATA_BUFSIZE;
      DataBuf.buf = buffer;
      EventTotal ++;
      //Step 4:Post a WSARecv request to begin receiving data on the socket
WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL);
While(TRUE)
{
      //Step 5:Wait for the overlapped I/O call to complete
      Index = WSAWaitForMultipleEvents(EventTotal,EventArray,FALSE,WSA_INFINITE,FALSE);
//Index should be 0,because we have only one event handle in EventArray
//Step 6:Reset the signaled event
WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
//Step 7:Determine the status of the overlapped request
WSAGetOverlappedResult(AcceptSocket, &AcceptOverlapped, &BytesTransferred, FALSE, &Flags);
//First check to see whether the peer has closed the connection, and if so, close the socket
if(BytesTransferred == 0){
     closesocket(AcceptSocket);
     WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
     Return;
}
//Do something with the received data.
//DataBuf contains the received data.
...
//Step 8:Post another WSARecv() request on the socket
Flags = 0;
ZeroMemory(&AcceptOverlapped,sizeof(WSAOVERLAPPED));
AcceptOverlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = Buffer;
WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped,NULL);
}
}
在Windows NT和Windows 2000中,重叠I/O模型也允许应用程序以一种重叠方式,实现对连接的接受。具体的做法是在监听套接字上调用AcceptEx函数。

完成例程
"完成例程"是我们的应用程序用来管理完成的重叠I / O请求的另一种方法。完成例程其实就是一些函数。设计宗旨是通过调用者的线程,为一个已完成的I / O请求提供服务。
void CALLBACK CompletionROUTINE(
       DWORD dwError, //表明了一个重叠操作(由l p O v e r l a p p e d指定)的完成状态是什么。
       DWORD cbTransferred,//实际传输的字节量
   LPWSAOVERLAPPED lpOverlapped,
   DWORD dwFlags // 0
);
在用一个完成例程提交的重叠请求,与用一个事件对象提交的重叠请求之间,存在着一项非常重要的区别。WSAOVERLAPPED结构的事件字段hEvent并未使用;
步骤:
1) 新建一个套接字,开始在指定端口上,监听一个进入的连接。
2) 接受一个进入的连接请求。
3) 为接受的套接字创建一个WSAOVERLAPPED结构。
4) 在套接字上投递一个异步WSARecv请求,方法是将WSAOVERLAPPED指定成为参数,同时提供一个完成例程。
5)

在将fAlertable参数设为TRUE的前提下,调用WSAWaitForMultipleEvents,并等待一个重叠I/O请求完成。重叠请求完
成后,完成例程会自动执行,而且WSAWaitForMultipleEven
ts会返回一个WSA_IO_COMPLETION。在完成例程内,可随一个完成例程一道,投递另一个重叠WSARecv请求。
6) 检查WSAWaitForMultipleEvents是否返回WSA_IO_COMPLETION。
7) 重复步骤5 )和6 )。

SOCKET AcceptSocket;
WSABUF DataBuf;
void main(void)
{
             WSAOVERLAPPED Overlapped;
//Step 1:Start Winsock, and set up a listening socket
     ...
//Step 2:Accept a new connection
     AcceptSocket = accept(ListenSocket, NULL, NULL);
//Step 3:Now that we have an accepted socket,start processing I/O using overlapped I/O with a completion routine.
//To get the overlapped I/O processing started,first submit an overlapped WSARECV() request.
     Flags = 0;
     ZeroMemory(&Overlapped, sizeof(WSAOVERLAPPED));
     DataBuf.len = DATA_BUFSIZE;
     DataBuf.buf = Buffer;
//Step 4: Post an asynchronous WSARecv() request on the socket by specifying the WSAOVERLAPPED structure
//as a parameter, and supply the WorkerRoutine function below as the completion routine
if(WSARecv(AcceptSocket,&DataBuf,1,&RecvBytes,&Flags,&Overlapped,WorkerRoutine) == SOCKET_ERROR){
     if(WSAGetLastError()!=WSA_IO_PENDING){
                   return;
}
     //Since the WSAWaitForMultipleEvents() API requires waiting on one or more event objects
//we will have to create a dummy event object. As an alternative, we can use SleepEx() instead.
EventArray[0] = WSACreatedEvent();
While(TRUE)
{  
            //Step 5:
Index = WSAWaitForMultipleEvents(1, EventArray, FALSE, WSA_INFINITE, TRUE);
//Step 6:
    if(Index = = WAIT_IO_COMPLETION) {
            //An overlapped request completion routine just completed.Continue servicing more completion rouines.
                   break;
}
else{
    //A bad error occurred - stop processing.
    Return;
}
}
}
}

void CALLBACK WorkerRoutine(DWORD Error,DWORD BytesTransferred,LPWSAOVERLAPPED overlapped,DWORD InFlags)
{
     DWORD SendBytes, RecvBytes;
     DWORD Flags;
     If(Error!=0||BytesTransferred == 0){
      //a bad error occurred on the socket
     closesocket(AcceptSocket);
     return;
}
//At this point, an overlapped WSARecv() request completed successfully.Now we can retrieve the received data that is
//contained in the variable DataBuf. After Processing the received data,We need to post another overlapped
//WSARecv() or WSASend() request.For Simplicity,we need to post another overlapped WSARecv() or WSASend()
//request.For Simplicity,we will post another WSARecv() request.
Flags = 0;
ZeroMemory(&Overlapped, sizeof(WSAOVERLAPPED));
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = Buffer;
if (WSARecv(AcceptSocket,*DataBuf,1,&RecvBytes,&Flags,&Overlapped,WorkerRoutine)==SOCKET_ERROR){
     if(WSAGetLastError()!=WSA_IO_PENDING){
    return;
}
}   
}

5完成端口模型
"
完成端口"模型是迄今为止最为复杂的一种I /
O模型。然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但不幸的是,该模型只适用于
Windows NT和Windows
2000操作系统。因其设计的复杂性,只有在你的应用程序需要同时管理数百乃至上千个套接字的时候,而且希望随着系统内安装的C P
U数量的增多,应用程序的性能也可以线性提升,才应考虑采用"完成端口"模型。要记住的一个基本准则是,假如要为Windows NT或Windows
2000开发高性能的服务器应用,同时希望为大量套接字I / O请求提供服务(We b服务器便是这方面的典型例子),那么I /
O完成端口模型便是最佳选择!

6. 个人感悟

按照我现在对这些模型的理解,个人觉得select模型和WSAAsyncSelect(异步选择)WSAEventSelect(事件选择)的差别并不是很大,都是在主线程保存一个socket数组,记录的是已经接受的clientsocket和listensocket,然后就有点区别了,select需要自己在主线程来通过阻塞的方式来判断是否有IO请求进来,而WSAAsyncSelect(异步选择)和WSAEventSelect(事件选择)是通过异步的方式,当有请求进来时会以信息的方式来通知,我们只要响应这个信息就行了,在信息响应函数中进行IO操作,将接受的数据写到程序的内存区。

重叠IO与上面最大的不同是当有IO数据接收时,数据被直接传入到了我们在重叠结构中提供的缓冲区中,而上面的是被传到了系统的缓冲区中然后程序再receive到自己的缓冲区中,当然,其实如果忽略这一点的话,上面的事件选择模型如果做成多线程的,在一个线程接收连接,投递请求,在另一个线程来处理请求。当然,这也只是我的一种理解,不知道能不能行的通。

重叠IO分为事件通知和完成例程俩种。基于事件通知的是专门开一个线程,在这个线程里专门accept,当一个client联入后,为它创建一个事件对象和重叠结构,然后调用WSARecv(),或者WSASend()然后这个线程的使命就完成了,继续监听端口等待新的client联进来。然后在其它线程等待着完成事件的触发,然后进行相应的操作。怎么感觉这个和上面的也差不了多少呢。另外要注意的是在这个模型中,一个waitformatipleevents最多只能监听64个事件的完成情况,那么,这个是不是也可以像完成端口一样创建多个线程来做woker线程,从而提高处理并发的能力呢,不知道这个是不是也像完成端口那样所有的线程共用一个信息队列,如果不是的话,这样做就会造成冲突。然后是基于完成例程的方式,这个是在一个线程投出去请求后,必须再在这个线程通过完成例程函数来处理请求,也就是说在一个线程要完成投递和处理请求的所有操作,那么这个也可以用多个线程,多个线程是分开各干各的,不会协同工作。

完成端口模型,也就是IOCP,传说中最高效的异步模型。个人感觉这个也应该是一种重叠IO模型,这个模型的思路是在一个通过一个完成端口,我们的所有请求都在这个端口中投递,然后可以创建多个worker线程,让这些线程轮流监听这个端口,一旦在这个端口中的信息队列中有信息投信了,我们就在这个worker线程中处理这个IO请求,这样的话,主线程呢在投递出几个accept后就悠哉悠哉的没事干了,worker线程轮流处理和投递IO请求。

最后我想我有点理解重叠的含义了,一个重叠结构呢对应的是一个IO操作,所以我们可以在一个socket下利用重叠结构同时投递多个IO请求,不知道这是不是就是重叠模型的含义。还要在实践中继续理解。。。。。。

WSAAsyncSelect(异步选择)WSAEventSelect(事件选择)

winsock的io模型(终极篇)的更多相关文章

  1. WinSock 重叠IO模型

    title: WinSock 重叠IO模型 tags: [WinSock 模型, 网络编程, 重叠IO模型] date: 2018-06-29 20:26:13 categories: Windows ...

  2. WinSock异步IO模型之Select

    如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的. Windows操作系统提供了五种I/O模型,分别是: ■ 选择(select): ■ 异步选择(WSAAsyncSelec ...

  3. Jakartase_IO流_ — Commons IO_(IO流终极篇)

    一.前言 Apache Commons IO是Apache基金会创建并维护的Java函数库. 它提供了许多类使得开发者的常见任务变得简单,同时减少重复代码 二.Commons IO 类库 2.1 Fi ...

  4. IO 模型知多少 | 代码篇

    引言 之前的一篇介绍IO 模型的文章IO 模型知多少 | 理论篇 比较偏理论,很多同学反应不是很好理解.这一篇咱们换一个角度,从代码角度来分析一下. socket 编程基础 开始之前,我们先来梳理一下 ...

  5. 第一篇:APUE-操作系统IO模型

    操作系统IO模型   操作系统IO模型 声明:如下内容是根据APUE和mycat两本著作中关于I/O模式的一些内容加上自己的一些理解整理而成,仅供学习使用. 本节内容 UNIX下可用的五种I/O模型 ...

  6. Linux IO模型(同步异步阻塞非阻塞等)的几篇好文章

    聊聊同步.异步.阻塞与非阻塞聊聊Linux 五种IO模型聊聊IO多路复用之select.poll.epoll详解 ​

  7. python基础27 -----python进程终结篇-----IO模型

    一.IO模型 1.IO模型分类 1.阻塞IO--------blocking IO 2.非阻塞IO------nonblocking IO 3. 多路复用IO------- multiplexing ...

  8. 第十篇.6、python并发编程之IO模型

    一 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非 ...

  9. Redis基础篇(二)高性能IO模型

    我们经常听到说Redis是单线程的,也会有疑问:为什么单线程的Redis能那么快? 这里要明白一点:Redis是单线程,主要是指Redis的网络IO和键值对读写是由一个线程来完成的,这也是Redis对 ...

随机推荐

  1. 如何将字符串去重复demo工具

    //方法一:使用集合的indexOf方法 public static void one(){ String string="aaaaaakkkkkkmnf";//需去重复的字符串s ...

  2. nginx的408错误

    client_header_timeout:Http核心模块指令,指令指定读取客户端请求头标题的超时时间.这里的超时是指一个请求头没有进入读取步骤,如果连接超过这个时间而客户端没有任何响应,Nginx ...

  3. mysql和php的内存问题

    最近给一个客户把他以前的数据转换到PHPSMC里去,因为他的数据太大出现一些问题,首先出现的是php内存问题,刚导时空白,我就在该也面的头部加上 error_reporting(E_ALL);打印所有 ...

  4. Docker命令大全

    1.容器生命周期管理 run  创建一个新的容器并运行一个命令 语法 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] OPTIONS说明: -a stdin ...

  5. 1、linux软件包管理

    linux软件包管理分为两种:RPM包管理和源码包管理,其中RPM包管理又有两种方式:①RPM命令管理,②YUM在线命令管理. RPM包依赖关系: 1.树形依赖 2.环形依赖 (用一条命令同时装来解决 ...

  6. Image与Bitmap的区别及相互转换

    1. Image.FromFile()返回的是某个继承自Image的具体类的对象,在这里,就是Bitmap或者Metafile其中之一.这应该算是factory pattern的一种形式.所以,Ima ...

  7. 全面了解POI操作Microsoft Office(Word、Excel、PowerPoint)

    POI 与 Microsoft Office 1. POI 简介 POI 是 Apache 下的 Jakata 项目的一个子项目,主要用于提供 java 操作 Microsoft Office 办公套 ...

  8. Linux下的service命令和chkconfig命令的原理

    CentOS下的service命令和chkconfig命令的原理 1.service命令的原理 service命令用来对服务进行启动和关闭,比如service mysqld start可以启动mysq ...

  9. kubernetes role

    https://kubernetes.io/docs/admin/authorization/rbac/

  10. nodemon 的坑

    1. 我的系统是ubuntu18.04.2 的 在使用过程中不知道什么为题 nodemon 运行的项目不在前台打印了项目, 我监听的端口 9302 一直在运行, 前台看不到 我想停止掉用 ps -ef ...