主頁 >  其他 > zookeeper原始碼決議--請求處理--PrepRequestProcessor

zookeeper原始碼決議--請求處理--PrepRequestProcessor

2022-01-23 07:35:56 其他

PrepRequestProcessor

1.從待處理請求佇列取出一個請求
2.如果是requestOfDeath
	退出
3.置空請求物件的事務頭,事務體,
4.請求未被過濾下,執行pRequestHelper
5.將請求交給下一級處理

pRequestHelper

對寫請求設定
對請求進行合法性檢查
按請求內容預先更新節點狀態資訊
為請求物件設定事務頭,事務體,事務摘要

對請求處理中遭遇錯誤的,采用拋出例外方式
對錯誤的寫請求,其事務頭,事務體包含錯誤及錯誤資訊,
對錯誤的請求,請求本身包含拋出例外資訊,

如果請求型別為OpCode.createContainer/OpCode.create/OpCode.create2
動態創建CreateRequest物件
//基于原始請求物件,
//對請求進行合法性檢查,
//預先對按請求進行節點更新&資料訪問,
//設定好請求物件的事務頭,事務體,事務摘要
pRequest2Txn(request.type, zks.getNextZxid(), request, create2Request, true);
如果請求型別為OpCode.createTTL
	CreateTTLRequest createTtlRequest = new CreateTTLRequest();
    pRequest2Txn(request.type, zks.getNextZxid(), request, createTtlRequest, true);
如果請求型別為OpCode.deleteContainer/OpCode.delete
    DeleteRequest deleteRequest = new DeleteRequest();
    pRequest2Txn(request.type, zks.getNextZxid(), request, deleteRequest, true);
如果請求型別為OpCode.setData
    SetDataRequest setDataRequest = new SetDataRequest();
    pRequest2Txn(request.type, zks.getNextZxid(), request, setDataRequest, true);
如果請求型別為OpCode.reconfig
    ReconfigRequest reconfigRequest = new ReconfigRequest();
    ByteBufferInputStream.byteBuffer2Record(request.request, reconfigRequest);
    pRequest2Txn(request.type, zks.getNextZxid(), request, reconfigRequest, true);
如果請求型別為OpCode.setACL
    SetACLRequest setAclRequest = new SetACLRequest();
    pRequest2Txn(request.type, zks.getNextZxid(), request, setAclRequest, true);
如果請求型別為OpCode.check
    CheckVersionRequest checkRequest = new CheckVersionRequest();
    pRequest2Txn(request.type, zks.getNextZxid(), request, checkRequest, true);
如果請求型別為OpCode.multi
    // 動態構造多操作請求,請求物體
    MultiOperationRecord multiRequest = new MultiOperationRecord();
    // 反向序列化得到資料物體
    try 
    {
              ByteBufferInputStream.byteBuffer2Record(request.request, multiRequest);
    } 
    catch (IOException e) 
    {
          	// 拋出例外時,仍然設定事務頭
              request.setHdr(
              	new TxnHeader(
            			request.sessionId, request.cxid, 
            			zks.getNextZxid(), Time.currentWallTime(), OpCode.multi));
              // 再次拋出
              throw e;
    }
          
    // 事務容器
    List<Txn> txns = new ArrayList<Txn>();
    // 獲取下一zxid
    long zxid = zks.getNextZxid();
    KeeperException ke = null;
    // 獲取每個子操作&最新狀態資訊,子操作父節點&最新狀態資訊
    Map<String, ChangeRecord> pendingChanges = getPendingChanges(multiRequest);
    // 設定請求的事務頭
    request.setHdr(
          	new TxnHeader(request.sessionId, request.cxid, zxid, Time.currentWallTime(), request.type));
    // 對每個子操作逐個處理
    for (Op op : multiRequest) 
    {
          	// 子操作的,請求物體
              Record subrequest = op.toRequestRecord();
              int type;
              Record txn;
              // 表示之前某個子操作遭遇例外
              if (ke != null) 
              {
              	 // 設定類別
                  type = OpCode.error;
                  // 設定事務體
                  txn = new ErrorTxn(Code.RUNTIMEINCONSISTENCY.intValue());
              } 
              else 
              {
                  try 
                  {
                  	//基于原始請求物件,
					//對請求進行合法性檢查,
					//預先對按請求進行節點更新&資料訪問,
					//設定好請求物件的事務頭,事務體,事務摘要
                    pRequest2Txn(op.getType(), zxid, request, subrequest, false);
                    // 子操作類別
                    type = op.getType();
                    // 獲得事務體
                    txn = request.getTxn();
                  } 
                  // 如果子操作在于例外
                  catch (KeeperException e) 
                  {
                  	// 例外記錄
                    ke = e;
                    // 類別記錄
                    type = OpCode.error;
                    // 用于記錄失敗的事務體
                    txn = new ErrorTxn(e.code().intValue());
                    if (e.code().intValue() > Code.APIERROR.intValue()) 
                    {
                          LOG.info(
                          	"Got user-level KeeperException when processing {} aborting" 
                          	+ " remaining multi ops. Error Path:{} Error:{}", 
                          	+ request.toString(), e.getPath(), e.getMessage());
                    }
			
			 		// 將例外資訊設定到請求物件
                    request.setException(e);
                    // 一旦一個子操作遭遇例外,執行回滾
                    // 回滾需要保證復合操作每個子操作對ChangeRecord的影響撤銷,
                    // 把ChangeRecord恢復到執行復合操作前
                    rollbackPendingChanges(zxid, pendingChanges);
                  }
              }

              try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) 
              {
                  BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
                  // 事務體物件序列化
                  txn.serialize(boa, "request");
                  ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
                  // 存盤到Txn物件集合
                  txns.add(new Txn(type, bb.array()));
              }
          }

 		  // 復合請求的事務體,也包含多個Txn分別對應每個子操作
          request.setTxn(new MultiTxn(txns));
          if (digestEnabled) 
          {
          	 // 設定事務摘要 
              setTxnDigest(request);
          }
 	}
如果請求型別為OpCode.createSession/OpCode.closeSession
   	// 本地會話不需追蹤?
    if (!request.isLocalSession()) 
    {
              pRequest2Txn(request.type, zks.getNextZxid(), request, null, true);
    }
如果請求型別為OpCode.sync/OpCode.exists/OpCode.getData/OpCode.getACL
    OpCode.getChildren/OpCode.getAllChildrenNumber/OpCode.getChildren2/OpCode.ping
    OpCode.setWatches/OpCode.setWatches2/OpCode.checkWatches/OpCode.removeWatches
    OpCode.getEphemerals/OpCode.multiRead/OpCode.addWatch/OpCode.addWatch
  	// 會話檢查
  	// 只讀請求不需要
  	zks.sessionTracker.checkSession(request.sessionId, request.getOwner());				

pRequest2TxnCreate(type, request, record, deserialize);

// 做新建節點前的合法性,權限,配額檢查
// 一切合法下,更新父節點,新建節點狀態資訊,
// 設定好本請求物件的事務頭,事務體,事務摘要資訊

if (deserialize) 
{
	// 從位元組流得到資料物件
	ByteBufferInputStream.byteBuffer2Record(request.request, record);
}

// 從資料物件提取資訊
if (type == OpCode.createTTL) 
{
    CreateTTLRequest createTtlRequest = (CreateTTLRequest) record;
    flags = createTtlRequest.getFlags();
    path = createTtlRequest.getPath();
    acl = createTtlRequest.getAcl();
    data = createTtlRequest.getData();
    ttl = createTtlRequest.getTtl();
} 
else 
{
    CreateRequest createRequest = (CreateRequest) record;
    flags = createRequest.getFlags();
    path = createRequest.getPath();
    acl = createRequest.getAcl();
    data = createRequest.getData();
    ttl = -1;
}

CreateMode createMode = CreateMode.fromFlag(flags);
// 合法性驗證,不合法通過拋出特定型別包含特定資訊例外來層層回退
validateCreateRequest(path, createMode, request, ttl);
// 父路徑
String parentPath = validatePathForCreate(path, request.sessionId);
// 權限
List<ACL> listACL = fixupACL(path, request.authInfo, acl);
// 父親路徑最新狀態
ChangeRecord parentRecord = getRecordForPath(parentPath);
// 權限檢查
zks.checkACL(
	request.cnxn, parentRecord.acl, 
	ZooDefs.Perms.CREATE, request.authInfo, path, listACL);
// 父親路徑下遭遇改變次數
int parentCVersion = parentRecord.stat.getCversion();
// 新節點完整路徑
if (createMode.isSequential()) 
{
    path = path + String.format(Locale.ENGLISH, "%010d", parentCVersion);
}

// 驗證路徑合法性
validatePath(path, request.sessionId);
try 
{
	// 如果要創建的路徑已經存在了
    if (getRecordForPath(path) != null) 
    {
    	// 拋出特定型別,包含特定資訊的例外
        throw new KeeperException.NodeExistsException(path);
    }
} 
catch (KeeperException.NoNodeException e) 
{
}
   
boolean ephemeralParent = EphemeralType.get(
	parentRecord.stat.getEphemeralOwner()) == EphemeralType.NORMAL;
// 這類父路徑不可包含子節點 
if (ephemeralParent) 
{
    throw new KeeperException.NoChildrenForEphemeralsException(path);
}
   
// 更新父節點遭遇變化次數
int newCversion = parentRecord.stat.getCversion() + 1;
// 檢查配額限制,配額限制超出時,通過拋出特定型別,包含特定資訊的例外來層層退出
zks.checkQuota(path, null, data, OpCode.create);
// 設定事務體
if (type == OpCode.createContainer) 
{
    request.setTxn(new CreateContainerTxn(path, data, listACL, newCversion));
} 
else if (type == OpCode.createTTL) 
{
    request.setTxn(new CreateTTLTxn(path, data, listACL, newCversion, ttl));
} 
else 
{
    request.setTxn(
    	new CreateTxn(path, data, listACL, createMode.isEphemeral(), newCversion));
}

TxnHeader hdr = request.getHdr();
long ephemeralOwner = 0;
// 創建模式--創建容器節點
if (createMode.isContainer()) 
{
      ephemeralOwner = EphemeralType.CONTAINER_EPHEMERAL_OWNER;
} 
// 創建模式--創建自帶生命期節點
else if (createMode.isTTL()) 
{
      ephemeralOwner = EphemeralType.TTL.toEphemeralOwner(ttl);
} 
// 創建模式--創建臨時節點【會話關閉,會話所屬臨時節點自動銷毀】
else if (createMode.isEphemeral()) 
{
      ephemeralOwner = request.sessionId;
}

// 創建節點狀態
StatPersisted s 
	= DataTree.createStat(hdr.getZxid(), hdr.getTime(), ephemeralOwner);
// 基于原有父節點的parentRecord得到新的
parentRecord = parentRecord.duplicate(request.getHdr().getZxid());
parentRecord.childCount++;
// 記錄了此節點下孩子累計新增孩子數量-變化為節點孩子變化
parentRecord.stat.setCversion(newCversion);
// 記錄了最后修改此節點狀態的事務id
parentRecord.stat.setPzxid(request.getHdr().getZxid());
// 更新整體和節點自身摘要資訊
parentRecord.precalculatedDigest 
	= precalculateDigest(DigestOpCode.UPDATE, parentPath, parentRecord.data, parentRecord.stat);
addChangeRecord(parentRecord);
// 一個節點可能包含多個關聯項
zks.outstandingChanges.add(c);
// 一個節點,只有一個路徑,也就只記錄一個關聯項,反映此節點最新狀態
zks.outstandingChangesForPath.put(c.path, c);
// 反映新建節點
ChangeRecord nodeRecord 
	= new ChangeRecord(request.getHdr().getZxid(), path, s, 0, listACL);
nodeRecord.data = data;
nodeRecord.precalculatedDigest = precalculateDigest(DigestOpCode.ADD, path, nodeRecord.data, s);
setTxnDigest(request, nodeRecord.precalculatedDigest);
request.setTxnDigest(new TxnDigest(digestCalculator.getDigestVersion(), preCalculatedDigest.treeDigest));
addChangeRecord(nodeRecord);

pRequest2Txn(request.type, zks.getNextZxid(), request, create2Request, true);

基于原始請求物件,
對請求進行合法性檢查,
預先對按請求進行節點更新&資料訪問,
設定好請求物件的事務頭,事務體,事務摘要

如果請求物件事務頭為null
	request.setHdr(
		new TxnHeader(request.sessionId, request.cxid, zxid, Time.currentWallTime(), type));
	如果類別為OpCode.create/OpCode.create2/OpCode.createTTL/OpCode.createContainer
		// 做新建節點前的合法性,權限,配額檢查
		// 一切合法下,更新父節點,新建節點狀態資訊,
		// 設定好本請求物件的事務頭,事務體,事務摘要資訊
		pRequest2TxnCreate(type, request, record, deserialize);
	如果類別為OpCode.deleteContainer
		String path = new String(request.request.array(), UTF_8);
        // 獲取父路徑,及驗證路徑
        String parentPath = getParentPathAndValidate(path);
        // 獲取洗掉路徑最新資訊
        ChangeRecord nodeRecord = getRecordForPath(path);
        // 如果洗掉節點包含子節點,不可洗掉
        if (nodeRecord.childCount > 0) 
        {
            throw new KeeperException.NotEmptyException(path);
        }
        
        // 要洗掉節點類別非法
        if (EphemeralType.get(nodeRecord.stat.getEphemeralOwner()) 
        	== EphemeralType.NORMAL) 
        {
            throw new KeeperException.BadVersionException(path);
        }
        
        // 獲取父節點最新狀態
        ChangeRecord parentRecord = getRecordForPath(parentPath);
        // 設定改請求的事務體
        request.setTxn(new DeleteTxn(path));
        // 基于parentRecord得到新的
        parentRecord = parentRecord.duplicate(request.getHdr().getZxid());
        parentRecord.childCount--;
        parentRecord.stat.setPzxid(request.getHdr().getZxid());
        parentRecord.precalculatedDigest 
        	= precalculateDigest(DigestOpCode.UPDATE, 
        		parentPath, parentRecord.data, parentRecord.stat);
        // 完成對父節點最新狀態的更新
        addChangeRecord(parentRecord);
        // 對洗掉節點,設定改節點ChangeRecord
        // 通過改ChangeRecord可辨別節點已被洗掉
        nodeRecord = new ChangeRecord(request.getHdr().getZxid(), path, null, -1, null);
        // 更新摘要資訊
        nodeRecord.precalculatedDigest = precalculateDigest(DigestOpCode.REMOVE, path);
        // 設定事務摘要
        setTxnDigest(request, nodeRecord.precalculatedDigest);
        // 完成對洗掉節點的狀態更新
        addChangeRecord(nodeRecord);
   	如果類別為OpCode.delete
   		// 會話檢查
   		zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
        DeleteRequest deleteRequest = (DeleteRequest) record;
        // 反向序列化得到資料物體
        if (deserialize) 
        {
            ByteBufferInputStream.byteBuffer2Record(request.request, deleteRequest);
        }
        
        // 要洗掉路徑
        String path = deleteRequest.getPath();
        // 要洗掉路徑父路徑
        String parentPath = getParentPathAndValidate(path);
        // 父路徑最新狀態
        ChangeRecord parentRecord = getRecordForPath(parentPath);
        // 權限檢查
        zks.checkACL(
        	request.cnxn, parentRecord.acl, ZooDefs.Perms.DELETE, request.authInfo, path, null);
        // 要洗掉路徑自身
        // 路徑不存在時,通過設定例外型別,例外資訊,層層退出
        ChangeRecord nodeRecord = getRecordForPath(path);
        // 版本檢查
        checkAndIncVersion(nodeRecord.stat.getVersion(), deleteRequest.getVersion(), path);
        // 有孩子的節點不可被洗掉
        if (nodeRecord.childCount > 0) 
        {
            throw new KeeperException.NotEmptyException(path);
        }
        // 設定事務體
        request.setTxn(new DeleteTxn(path));
        // 基于parentRecord得到新的
        parentRecord = parentRecord.duplicate(request.getHdr().getZxid());
        // 更新父節點最新狀態資訊
        // 狀態--孩子數量
        parentRecord.childCount--;
        // 狀態--最后對其修改的事務的id
        parentRecord.stat.setPzxid(request.getHdr().getZxid());
        // 更新摘要
        parentRecord.precalculatedDigest 
        	= precalculateDigest(DigestOpCode.UPDATE, 
        	parentPath, parentRecord.data, parentRecord.stat);
        addChangeRecord(parentRecord);
        // 為要洗掉節點,動態構造ChangeRecord
        nodeRecord = new ChangeRecord(request.getHdr().getZxid(), path, null, -1, null);
        // 更新摘要
        nodeRecord.precalculatedDigest = precalculateDigest(DigestOpCode.REMOVE, path);
        // 設定事務摘要
        setTxnDigest(request, nodeRecord.precalculatedDigest);
        addChangeRecord(nodeRecord);
 	如果類別為OpCode.setData
 		// 檢查會話
 		zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
        // 事務體
        SetDataRequest setDataRequest = (SetDataRequest) record;
        // 反向序列化得到資料物件
        if (deserialize) 
        {
            ByteBufferInputStream.byteBuffer2Record(request.request, setDataRequest);
        }
        // 路徑
        path = setDataRequest.getPath();
        // 驗證路徑合法性
        validatePath(path, request.sessionId);
        // 獲取此路徑最新資訊
        nodeRecord = getRecordForPath(path);
        // 權限檢查
        zks.checkACL(
        	request.cnxn, nodeRecord.acl, ZooDefs.Perms.WRITE, request.authInfo, path, null);
        // 配額檢查
        zks.checkQuota(path, nodeRecord.data, setDataRequest.getData(), OpCode.setData);
        // 版本檢查
        int newVersion = 
        	checkAndIncVersion(nodeRecord.stat.getVersion(), setDataRequest.getVersion(), path);
        // 設定事務體
        request.setTxn(new SetDataTxn(path, setDataRequest.getData(), newVersion));
        // 基于nodeRecode得到新的
        nodeRecord = nodeRecord.duplicate(request.getHdr().getZxid());
        // 新的相比舊的,版本變了
        nodeRecord.stat.setVersion(newVersion);
        // 修改時間變了
        nodeRecord.stat.setMtime(request.getHdr().getTime());
        // 最后修改的事務id變了
        nodeRecord.stat.setMzxid(zxid);
        // 節點資料內容變了
        nodeRecord.data = setDataRequest.getData();
        // 更新摘要
        nodeRecord.precalculatedDigest 
        	= precalculateDigest(DigestOpCode.UPDATE, path, nodeRecord.data, nodeRecord.stat);
        // 設定事務摘要
        setTxnDigest(request, nodeRecord.precalculatedDigest);
        addChangeRecord(nodeRecord);
    如果類別為OpCode.setACL
    	// 檢查會話
    	zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
        // 事務體
        SetACLRequest setAclRequest = (SetACLRequest) record;
        // 反向序列化得到資料物件
        if (deserialize) 
        {
            ByteBufferInputStream.byteBuffer2Record(request.request, setAclRequest);
        }
        // 路徑
        path = setAclRequest.getPath();
        // 驗證路徑
        validatePath(path, request.sessionId);
        // 權限串列
        List<ACL> listACL = fixupACL(path, request.authInfo, setAclRequest.getAcl());
        // 路徑最新狀態
        nodeRecord = getRecordForPath(path);
        // 權限檢查
        zks.checkACL(
        	request.cnxn, nodeRecord.acl, ZooDefs.Perms.ADMIN, request.authInfo, path, listACL);
        // 版本檢查
        newVersion 
        	= checkAndIncVersion(nodeRecord.stat.getAversion(), setAclRequest.getVersion(), path);
        // 設定事務體
        request.setTxn(new SetACLTxn(path, listACL, newVersion));
        // 基于nodeRecord得到新的
        nodeRecord = nodeRecord.duplicate(request.getHdr().getZxid());
        // 設定新的版本
        nodeRecord.stat.setAversion(newVersion);
        // 更新摘要資訊
        nodeRecord.precalculatedDigest 
        	= precalculateDigest(DigestOpCode.UPDATE, path, nodeRecord.data, nodeRecord.stat);
        // 設定事務摘要
        setTxnDigest(request, nodeRecord.precalculatedDigest);
        addChangeRecord(nodeRecord);
   	如果型別為OpCode.createSession
   		request.request.rewind();
   		// 獲取超時時間?
        int to = request.request.getInt();
        // 設定事務體
        request.setTxn(new CreateSessionTxn(to));
        request.request.rewind();
        // 會話追蹤
        zks.sessionTracker.trackSession(request.sessionId, to);
        // 會話擁有者,為請求擁有者
        zks.setOwner(request.sessionId, request.getOwner());
    如果型別為OpCode.closeSession
    	// 當前時間
    	long startTime = Time.currentElapsedTime();
        synchronized (zks.outstandingChanges) 
        {
        	// 獲取屬于此會話的所有臨時節點
            Set<String> es = zks.getZKDatabase().getEphemerals(request.sessionId);
            // 對所有排隊中ChangeRecord
            for (ChangeRecord c : zks.outstandingChanges) 
            {
            	// 表示待實施請求中,已經包含洗掉某路徑請求
                if (c.stat == null) 
                {
                	// 將此會話下已經規劃為洗掉的路徑從這里的臨時節點中去掉,避免重復洗掉
                    es.remove(c.path);
                } 
                // 表示待實施請求中,包含某個路徑屬于此臨時會話
                else if (c.stat.getEphemeralOwner() == request.sessionId) 
                {
                	// 將改路徑加入這里的臨時節點,放置漏掉屬于此會話的待實施的臨時節點,
                    es.add(c.path);
                }
            }
			
			// 對此會話的每個臨時節點,對其父節點進行更新
            for (String path2Delete : es) 
            {
                if (digestEnabled) 
                {
                	// 獲取洗掉節點,父節點&驗證
                    parentPath = getParentPathAndValidate(path2Delete);
                    // 獲取父節點最新狀態
                    parentRecord = getRecordForPath(parentPath);
                    // 基于parentRecord得到新的
                    parentRecord = parentRecord.duplicate(request.getHdr().getZxid());
                    // 更新修改父節點孩子的事務id
                    parentRecord.stat.setPzxid(request.getHdr().getZxid());
                    // 更新摘要
                    parentRecord.precalculatedDigest 
                    	= precalculateDigest(DigestOpCode.UPDATE, 
                    		parentPath, parentRecord.data, parentRecord.stat);
                    addChangeRecord(parentRecord);
                }
                
                // 動態構造要洗掉節點的nodeRecord
                nodeRecord = 
                	new ChangeRecord(request.getHdr().getZxid(), path2Delete, null, 0, null);
                // 更新摘要
                nodeRecord.precalculatedDigest 
                	= precalculateDigest(DigestOpCode.REMOVE, path2Delete);
                addChangeRecord(nodeRecord);
            }

            if (ZooKeeperServer.isCloseSessionTxnEnabled()) 
            {
            	// 設定事務體
                request.setTxn(new CloseSessionTxn(new ArrayList<String>(es)));
            }
            
            // 設定會話狀態為關閉中
            zks.sessionTracker.setSessionClosing(request.sessionId);
        }

        ServerMetrics.getMetrics()
        	.CLOSE_SESSION_PREP_TIME.add(Time.currentElapsedTime() - startTime);
	如果型別為OpCode.check
		// 會話檢查
		zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
        CheckVersionRequest checkVersionRequest = (CheckVersionRequest) record;
        // 反向序列化得到資料物體
        if (deserialize) 
        {
            ByteBufferInputStream.byteBuffer2Record(request.request, checkVersionRequest);
        }
        // 獲取路徑
        path = checkVersionRequest.getPath();
        // 驗證路徑
        validatePath(path, request.sessionId);
        // 獲取路徑最新資訊
        nodeRecord = getRecordForPath(path);
        // 權限檢查
        zks.checkACL(
        	request.cnxn, nodeRecord.acl, ZooDefs.Perms.READ, request.authInfo, path, null);
        // 設定事務體
        request.setTxn(
        	new CheckVersionTxn(path, 
        		checkAndIncVersion(nodeRecord.stat.getVersion(), 
        		checkVersionRequest.getVersion(), null));

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

標籤:其他

上一篇:TiDB 在國信證券海量資料高并發場景中的實踐

下一篇:基于Flink實時數倉——DWS 層-地區主題表(8)

標籤雲
其他(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)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more