主頁 > 軟體工程 > iocp求助,全部分拿出來了

iocp求助,全部分拿出來了

2020-09-15 01:52:14 軟體工程

#include "stdafx.h"
#include<Winsock2.h>
#include<iostream>
#include<assert.h>//here
#include<MSWSock.h>
#include<vector>
using namespace std;
#define RELEASE(x) {if(x != NULL ){delete x;x=NULL;}}
#define RELEASE_HANDLE(x) {if(x != NULL && x!=INVALID_HANDLE_VALUE){ CloseHandle(x);x = NULL;}}
#define RELEASE_SOCKET(x) {if(x !=INVALID_SOCKET) { closesocket(x);x=INVALID_SOCKET;}}
template<typename t>
void RemoveAt(t vec, int num)
{
t::iterator it = vec.begin() + num;
vec.erase(it);
}
typedef enum _OPERATION_TYPE
{
ACCEPT_POSTED, 
SEND_POSTED, 
RECV_POSTED,
NULL_POSTED

}OPERATION_TYPE;
typedef struct _PER_IO_CONTEXT
{
OVERLAPPED m_Overlapped; 
SOCKET m_sockAccept;
WSABUF m_wsaBuf;
char m_szBuffer[8192];
OPERATION_TYPE m_OpType;
_PER_IO_CONTEXT()
{
ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
ZeroMemory(m_szBuffer, 8192);
m_sockAccept = INVALID_SOCKET;
m_wsaBuf.buf = m_szBuffer;
m_wsaBuf.len =8192;
m_OpType = NULL_POSTED;
}
~_PER_IO_CONTEXT()
{
if (m_sockAccept != INVALID_SOCKET)
{
closesocket(m_sockAccept);
m_sockAccept = INVALID_SOCKET;
}
}
void ResetBuffer()
{
ZeroMemory(m_szBuffer, 8192);
}
} PER_IO_CONTEXT;
typedef struct _PER_SOCKET_CONTEXT
{
SOCKET m_Socket; 
SOCKADDR_IN m_ClientAddr; 
vector<_PER_IO_CONTEXT*> m_arrayIoContext; 
_PER_SOCKET_CONTEXT()
{
m_Socket = INVALID_SOCKET;
memset(&m_ClientAddr, 0, sizeof(m_ClientAddr));
}
~_PER_SOCKET_CONTEXT()
{
if (m_Socket != INVALID_SOCKET)
{
closesocket(m_Socket);
m_Socket = INVALID_SOCKET;
}
for (int i = 0; i<m_arrayIoContext.size(); i++)
{
delete m_arrayIoContext[i];
}
m_arrayIoContext.clear();
}
_PER_IO_CONTEXT* GetNewIoContext()
{
_PER_IO_CONTEXT* p = new _PER_IO_CONTEXT;
m_arrayIoContext.push_back(p);
return p;
}
void RemoveContext(_PER_IO_CONTEXT* pContext)
{
assert(pContext != NULL);
for (int i = 0; i < m_arrayIoContext.size(); i++)
{
if (pContext == m_arrayIoContext[i])
{
delete pContext;
pContext = NULL;
RemoveAt(m_arrayIoContext, i);
break;
}
}
}
} PER_SOCKET_CONTEXT;
class C
{
public:

HANDLE m_hShutdownEvent;
HANDLE m_hIOCompletionPort;
HANDLE* m_phWorkerThreads;
int m_nThreads;
string m_strIP; 
int m_nPort; 
CRITICAL_SECTION m_csContextList; 
vector<PER_SOCKET_CONTEXT*> m_arrayClientContext; 
PER_SOCKET_CONTEXT* m_pListenContext; 
LPFN_ACCEPTEX m_lpfnAcceptEx; 
LPFN_GETACCEPTEXSOCKADDRS m_lpfnGetAcceptExSockAddrs;
}C;
int _GetNoOfProcessors()
{
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwNumberOfProcessors + 1;
}
bool _IsSocketAlive(SOCKET s)
{
int nByteSent = send(s, "", 0, 0);
if (-1 == nByteSent)
{
return false;
}
return true;
}
bool _PostSend(PER_IO_CONTEXT* pIoContext, char* buf)
{
size_t leng = strlen(buf);
DWORD dwBytes = 0;
WSABUF p_wbuf;
p_wbuf.buf = new char[leng];
p_wbuf.len = leng;
memcpy(p_wbuf.buf, buf, sizeof(char)*leng);
OVERLAPPED *p_ol = &pIoContext->m_Overlapped;
pIoContext->m_OpType = SEND_POSTED;
if (SOCKET_ERROR == WSASend(pIoContext->m_sockAccept, &p_wbuf, 1,&dwBytes,NULL, p_ol, NULL) && WSA_IO_PENDING != WSAGetLastError())
{
return false;
}
return true;
}
void _DoSend(PER_SOCKET_CONTEXT *pSocketContext, PER_IO_CONTEXT *pIoContext)
{
EnterCriticalSection(&C.m_csContextList);
pSocketContext->RemoveContext(pIoContext);
LeaveCriticalSection(&C.m_csContextList);
}
bool _DoRecv(PER_IO_CONTEXT* pIoContext)
{
DWORD dwFlags = 0;
DWORD dwBytes = 0;
WSABUF *p_wbuf = &pIoContext->m_wsaBuf;
OVERLAPPED *p_ol = &pIoContext->m_Overlapped;
cout << (*p_wbuf).buf;
pIoContext->ResetBuffer();
pIoContext->m_OpType = RECV_POSTED;
if (SOCKET_ERROR == WSARecv(pIoContext->m_sockAccept, p_wbuf, 1, &dwBytes, &dwFlags, p_ol, NULL) && WSA_IO_PENDING != WSAGetLastError())
{
return false;
}
return true;
}
void _AddToContextList(PER_SOCKET_CONTEXT *pHandleData)
{
EnterCriticalSection(&C.m_csContextList);
C.m_arrayClientContext.push_back(pHandleData);
LeaveCriticalSection(&C.m_csContextList);
}
void _RemoveContext(PER_SOCKET_CONTEXT *pSocketContext)
{
EnterCriticalSection(&C.m_csContextList);
for (int i = 0; i<C.m_arrayClientContext.size(); i++)
{
if (pSocketContext == C.m_arrayClientContext[i])
{
RELEASE(pSocketContext);
RemoveAt(C.m_arrayClientContext,i);
break;
}
}
LeaveCriticalSection(&C.m_csContextList);
}
bool IsSocketInContextList(PER_SOCKET_CONTEXT* pSocketContext)
{
vector<PER_SOCKET_CONTEXT*>::iterator it_find = C.m_arrayClientContext.begin();
for (; it_find != C.m_arrayClientContext.end(); it_find++)
{
if (*it_find == pSocketContext)
{
return true;
}
}
return false;
}
void _ClearContextList()
{
EnterCriticalSection(&C.m_csContextList);
for (int i = 0; i<C.m_arrayClientContext.size(); i++)
{
delete C.m_arrayClientContext[i];
}
C.m_arrayClientContext.clear();
LeaveCriticalSection(&C.m_csContextList);
}
bool HandleError(PER_SOCKET_CONTEXT *pContext, const DWORD& dwErr)
{
if (WAIT_TIMEOUT == dwErr)
{
if (!_IsSocketAlive(pContext->m_Socket))
{
_RemoveContext(pContext);
return true;
}
else
{
return true;
}
}
else if (ERROR_NETNAME_DELETED == dwErr)
{
_RemoveContext(pContext);
return true;
}
else
{
return false;
}
}
bool _AssociateWithIOCP(PER_SOCKET_CONTEXT *pContext)
{
HANDLE hTemp = CreateIoCompletionPort((HANDLE)pContext->m_Socket, C.m_hIOCompletionPort, (DWORD)pContext, 0);
if (NULL == hTemp)
{
return false;
}
return true;
}
bool _PostAccept(PER_IO_CONTEXT* pAcceptIoContext)
{
assert(INVALID_SOCKET != C.m_pListenContext->m_Socket);
DWORD dwBytes = 0;
pAcceptIoContext->m_OpType = ACCEPT_POSTED;
WSABUF *p_wbuf = &pAcceptIoContext->m_wsaBuf;
OVERLAPPED *p_ol = &pAcceptIoContext->m_Overlapped;
pAcceptIoContext->m_sockAccept = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET == pAcceptIoContext->m_sockAccept)
{
return false;
}
if (FALSE == C.m_lpfnAcceptEx(C.m_pListenContext->m_Socket, pAcceptIoContext->m_sockAccept, p_wbuf->buf, p_wbuf->len - ((sizeof(SOCKADDR_IN) + 16) * 2),sizeof(SOCKADDR_IN) + 16, sizeof(SOCKADDR_IN) + 16, &dwBytes, p_ol))
{
if (WSA_IO_PENDING != WSAGetLastError())
{
return false;
}
}
return true;
}
bool _DoAccpet(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT* pIoContext)
{
SOCKADDR_IN* ClientAddr = NULL;
SOCKADDR_IN* LocalAddr = NULL;
int remoteLen = sizeof(SOCKADDR_IN), localLen = sizeof(SOCKADDR_IN);
PER_SOCKET_CONTEXT* pNewSocketContext = new PER_SOCKET_CONTEXT;
pNewSocketContext->m_Socket = pIoContext->m_sockAccept;
C.m_lpfnGetAcceptExSockAddrs(pIoContext->m_wsaBuf.buf, pIoContext->m_wsaBuf.len - ((sizeof(SOCKADDR_IN) + 16) * 2),sizeof(SOCKADDR_IN) + 16, sizeof(SOCKADDR_IN) + 16, (LPSOCKADDR*)&LocalAddr, &localLen, (LPSOCKADDR*)&ClientAddr, &remoteLen);
memcpy(&(pNewSocketContext->m_ClientAddr), ClientAddr, sizeof(SOCKADDR_IN));
if (false == _AssociateWithIOCP(pNewSocketContext))
{
RELEASE(pNewSocketContext);
return false;
}
PER_IO_CONTEXT* pNewIoContext = pNewSocketContext->GetNewIoContext();
pNewIoContext->m_OpType = RECV_POSTED;
pNewIoContext->m_sockAccept = pNewSocketContext->m_Socket;
/*if (false == _DoRecv(pNewIoContext))
{
pNewSocketContext->RemoveContext(pNewIoContext);
return false;
}*/
_AddToContextList(pNewSocketContext);
pIoContext->ResetBuffer();
return _PostAccept(pIoContext);
}
void _WorkerThread()
{
OVERLAPPED *pOverlapped = NULL;
PER_SOCKET_CONTEXT *pSocketContext = NULL;
DWORD dwBytesTransfered = 0;
while (WAIT_OBJECT_0 != WaitForSingleObject(C.m_hShutdownEvent, 0))
{
BOOL bReturn = GetQueuedCompletionStatus(C.m_hIOCompletionPort,&dwBytesTransfered,(PULONG_PTR)&pSocketContext,&pOverlapped,INFINITE);
if (NULL == (DWORD)pSocketContext)
{
break;
}
if (!bReturn)
{
DWORD dwErr = GetLastError();
if (!HandleError(pSocketContext, dwErr))
{
break;
}
continue;
}
else
{
PER_IO_CONTEXT* pIoContext = CONTAINING_RECORD(pOverlapped, PER_IO_CONTEXT, m_Overlapped);
if ((0 == dwBytesTransfered) && (RECV_POSTED == pIoContext->m_OpType || SEND_POSTED == pIoContext->m_OpType))
{
_RemoveContext(pSocketContext);
continue;
}
else
{
switch (pIoContext->m_OpType)
{
case ACCEPT_POSTED:
{
_DoRecv(pIoContext);
_DoAccpet(pSocketContext, pIoContext);char k[] = "123456";
cout << C.m_arrayClientContext.size();
}
break;
case RECV_POSTED:
{
_DoRecv(pIoContext);
_PostSend(pIoContext, k);
}
break;
case SEND_POSTED:
{
_DoSend(pSocketContext, pIoContext);
}
break;
default:
break;
}
}
}
}
}
void _InitializeIOCP()
{
C.m_hIOCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
C.m_nThreads = 2 * _GetNoOfProcessors();
C.m_phWorkerThreads = new HANDLE[C.m_nThreads];
DWORD nThreadID;
for (int i = 0; i < C.m_nThreads; i++)
{
C.m_phWorkerThreads[i] = ::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)_WorkerThread, 0, 0, &nThreadID);
}
}
為什么作業執行緒recv GetQueuedCompletionStatus卻收不到recv_posted,還有為什么wsasend發不出去了,回傳-1,wsagetlasterror回傳10057??求助巨佬!

uj5u.com熱心網友回復:

使用IO完成埠IOCP與執行緒池創建高性能服務器


uj5u.com熱心網友回復:


當年也被iocp坑了好久。2010年,現在已經沒啥問題了。多搜集iocp的專案代碼,最好是成熟穩定的,研究個幾天就通了

uj5u.com熱心網友回復:

這個不錯,非常感謝!

uj5u.com熱心網友回復:

但是我想知道上面代碼出了什么問題...

uj5u.com熱心網友回復:

參考 1 樓 zgl7903的回復:
使用IO完成埠IOCP與執行緒池創建高性能服務器

wsasend用法似乎也沒錯 但就是10057

uj5u.com熱心網友回復:


//
// MessageId: WSAENOTCONN
//
// MessageText:
//
// A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.
//
#define WSAENOTCONN                      10057L



uj5u.com熱心網友回復:

參考 6 樓 zgl7903的回復:

//
// MessageId: WSAENOTCONN
//
// MessageText:
//
// A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.
//
#define WSAENOTCONN                      10057L


為啥會連接錯誤啊...

uj5u.com熱心網友回復:

參考 6 樓 zgl7903的回復:

//
// MessageId: WSAENOTCONN
//
// MessageText:
//
// A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.
//
#define WSAENOTCONN                      10057L


是要重建個重疊結構嗎

uj5u.com熱心網友回復:

用accept實作了,但是acceptex還是不行

uj5u.com熱心網友回復:

順便問一下,accept會多大程度的影響效率

uj5u.com熱心網友回復:

https://bbs.csdn.net/topics/392748259

uj5u.com熱心網友回復:

m_lpfnAcceptEx沒有賦值啊
// 加載AcceptEx函式
void LoadAcceptEx() {
GUID guidAcceptEx = WSAID_ACCEPTEX;
DWORD dwBytes;
WSAIoctl(m_hListenSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx, sizeof(guidAcceptEx), &m_lpfnAcceptEx, sizeof(m_lpfnAcceptEx), &dwBytes, NULL, NULL);
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/40500.html

標籤:網絡編程

上一篇:求幫助,非常著急啊!!

下一篇:MFC Mat 轉 HBitmap,顯示不出圖片,總是一片黑

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • Git本地庫既關聯GitHub又關聯Gitee

    創建代碼倉庫 使用gitee舉例(github和gitee差不多) 1.在gitee右上角點擊+,選擇新建倉庫 ? 2.選擇填寫倉庫資訊,然后進行創建 ? 3.服務端已經準備好了,本地開始作準備 (1)Git 全域設定 git config --global user.name "成鈺" git c ......

    uj5u.com 2020-09-10 05:04:14 more
  • CODING DevOps 代碼質量實戰系列第二課,相約周三

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。**《DevOps 代碼質量實戰(PHP 版)》**為 CODING DevOps 代碼質量實戰系列的第二課,同時也是本系列的 PHP ......

    uj5u.com 2020-09-10 05:07:43 more
  • 推薦Scrum書籍

    推薦Scrum書籍 直接上干貨,推薦書籍清單如下(推薦有順序的哦) Scrum指南 Scrum精髓 Scrum敏捷軟體開發 Scrum捷徑 硝煙中的Scrum和XP : 我們如何實施Scrum 敏捷軟體開發:Scrum實戰指南 Scrum要素 大規模Scrum:大規模敏捷組織的設計 用戶故事地圖 用 ......

    uj5u.com 2020-09-10 05:07:45 more
  • CODING DevOps 代碼質量實戰系列最后一課,周四發車

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。 **《DevOps 代碼質量實戰(Java 版)》**為 CODING DevOps 代碼質量實戰系列的最后一課,同時也是本系列的 ......

    uj5u.com 2020-09-10 05:07:52 more
  • 敏捷軟體工程實踐書籍

    Scrum轉型想要做好,第一步先了解并真正落實Scrum,那么我推薦的Scrum書籍是要看懂并實踐的。第二步是團隊的工程實踐要做扎實。 下面推薦工程實踐書單: 重構:改善既有代碼的設計 決議極限編程 : 擁抱變化 代碼整潔代碼 程式員的職業素養 修改代碼的藝術 撰寫可讀代碼的藝術 測驗驅動開發 : ......

    uj5u.com 2020-09-10 05:07:55 more
  • Jenkins+svn+nginx實作windows環境自動部署vue前端專案

    前面文章介紹了Jenkins+svn+tomcat實作自動化部署,現在終于有空抽時間出來寫下Jenkins+svn+nginx實作自動部署vue前端專案。 jenkins的安裝和配置已經在前面文章進行介紹,下面介紹實作vue前端專案需要進行的哪些額外的步驟。 注意:在安裝jenkins和nginx的 ......

    uj5u.com 2020-09-10 05:08:49 more
  • CODING DevOps 微服務專案實戰系列第一課,明天等你

    CODING DevOps 微服務專案實戰系列第一課**《DevOps 微服務專案實戰:DevOps 初體驗》**將由 CODING DevOps 開發工程師 王寬老師 向大家介紹 DevOps 的基本理念,并探討為什么現代開發活動需要 DevOps,同時將以 eShopOnContainers 項 ......

    uj5u.com 2020-09-10 05:09:14 more
  • CODING DevOps 微服務專案實戰系列第二課來啦!

    近年來,工程專案的結構越來越復雜,需要接入合適的持續集成流水線形式,才能滿足更多變的需求,那么如何優雅地使用 CI 能力提升生產效率呢?CODING DevOps 微服務專案實戰系列第二課 《DevOps 微服務專案實戰:CI 進階用法》 將由 CODING DevOps 全堆疊工程師 何晨哲老師 向 ......

    uj5u.com 2020-09-10 05:09:33 more
  • CODING DevOps 微服務專案實戰系列最后一課,周四開講!

    隨著軟體工程越來越復雜化,如何在 Kubernetes 集群進行灰度發布成為了生產部署的”必修課“,而如何實作安全可控、自動化的灰度發布也成為了持續部署重點關注的問題。CODING DevOps 微服務專案實戰系列最后一課:**《DevOps 微服務專案實戰:基于 Nginx-ingress 的自動 ......

    uj5u.com 2020-09-10 05:10:00 more
  • CODING 儀表盤功能正式推出,實作作業資料可視化!

    CODING 儀表盤功能現已正式推出!該功能旨在用一張張統計卡片的形式,統計并展示使用 CODING 中所產生的資料。這意味著無需額外的設定,就可以收集歸納寶貴的作業資料并予之量化分析。這些海量的資料皆會以圖表或串列的方式躍然紙上,方便團隊成員隨時查看各專案的進度、狀態和指標,云端協作迎來真正意義上 ......

    uj5u.com 2020-09-10 05:11:01 more
最新发布
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:41:12 more
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:35:34 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:05:44 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:00:18 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:20:31 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:55 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:18:51 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:00 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:17:55 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:12:06 more