主頁 > 企業開發 > USBReadFile()替換串行通信設備使用的串行埠代碼超時

USBReadFile()替換串行通信設備使用的串行埠代碼超時

2021-11-08 21:48:21 企業開發

我正在為熱敏收據列印機擴展收據列印串行埠 (COM) 介面,以便在不需要虛擬串行埠的情況下使用 USB 介面。我有一個作業原型,它將列舉連接的 USB 設備,找到具有特定供應商 ID 和產品 ID 的設備的 USB 路徑,并使用CreateFile().

現有的串行埠代碼使用封裝在一組函式中的 Windows API。我采用的方法是使用相同的函式集添加額外的代碼,但這取決于 USB 連接而不是串行埠連接。我以前使用相同的方法允許通過串行埠或 WiFi/LAN 連接使用廚房列印機,并且成功地對現有代碼進行了最小的更改。

不幸的是,使用函式庫的現有代碼取決于使用ReadFile()指定超時的函式,這樣如果熱敏列印機在合理的時間內沒有回應狀態請求,應用程式可以將其標記為關閉并允許操作繼續或使用備份或輔助列印機。

如何指定使用 USB 路徑名打開與通信設備的連接ReadFile()的檔案句柄上的超時CreateFile()

需要考慮的是,這是用于多個串行通信設備(收據列印機、廚房列印機、秤等)的多執行緒代碼,但是執行緒將獨占訪問特定設備(廚房列印功能打開廚房列印機的串行埠)僅,秤讀取功能僅打開串行埠以進行秤等)。

在現有的串行埠代碼中,用于設定超時的函式SetCommTimeouts(),用于打開的串行埠連接CreateFile()不適用于打開的 USB 連接CreateFile()(請參閱SetupComm, SetCommState, SetCommTimeouts fail with USB device)。這意味著需要一些其他機制來提供一種方法來允許由于使用 USB 設備路徑名時超時而導致的 I/O 故障。

我們使用以下代碼段來打開一個串行埠,無論是硬體 COM 埠還是模擬硬體 COM 埠的虛擬串行埠:

// see Microsoft document HOWTO: Specify Serial Ports Larger than COM9.
// https://support.microsoft.com/en-us/kb/115831
// CreateFile() can be used to get a handle to a serial port. The "Win32 Programmer's Reference" entry for "CreateFile()"
// mentions that the share mode must be 0, the create parameter must be OPEN_EXISTING, and the template must be NULL. 
//
// CreateFile() is successful when you use "COM1" through "COM9" for the name of the file;
// however, the value INVALID_HANDLE_VALUE is returned if you use "COM10" or greater. 
//
// If the name of the port is \\.\COM10, the correct way to specify the serial port in a call to
// CreateFile() is "\\\\.\\COM10".
//
// NOTES: This syntax also works for ports COM1 through COM9. Certain boards will let you choose
//        the port names yourself. This syntax works for those names as well.
wsprintf(wszPortName, TEXT("\\\\.\\COM%d"), usPortId);

/* Open the serial port. */
/* avoid to failuer of CreateFile */
for (i = 0; i < 10; i  ) {
    hHandle = CreateFile (wszPortName, /* Pointer to the name of the port, PifOpenCom() */
                      GENERIC_READ | GENERIC_WRITE,  /* Access (read-write) mode */
                      0,            /* Share mode */
                      NULL,         /* Pointer to the security attribute */
                      OPEN_EXISTING,/* How to open the serial port */
                      0,            /* Port attributes */
                      NULL);        /* Handle to port with attribute */
                                    /* to copy */

    /* If it fails to open the port, return FALSE. */
    if ( hHandle == INVALID_HANDLE_VALUE )   {    /* Could not open the port. */
        dwError = GetLastError ();
        if (dwError == ERROR_FILE_NOT_FOUND || dwError == ERROR_INVALID_NAME || dwError == ERROR_ACCESS_DENIED) {
            LeaveCriticalSection(&g_SioCriticalSection);
            // the COM port does not exist. probably a Virtual Serial Communications Port
            // from a USB device which was either unplugged or turned off.
            // or the COM port or Virtual Serial Communications port is in use by some other application.
            return PIF_ERROR_COM_ACCESS_DENIED;
        }
        PifLog (MODULE_PIF_OPENCOM, LOG_ERROR_PIFSIO_CODE_01);
        PifLog (MODULE_ERROR_NO(MODULE_PIF_OPENCOM), (USHORT)dwError);
        PifLog(MODULE_DATA_VALUE(FAULT_AT_PIFOPENCOM), usPortId);
        PifSleep(500);
    } else {
        break;
    }
}
if ( hHandle == INVALID_HANDLE_VALUE )   {    /* Could not open the port. */
    wsprintf(wszDisplay, TEXT("CreateFile, COM%d, Last Error =%d\n"), usPortId, dwError);
    OutputDebugString(wszDisplay);
    LeaveCriticalSection(&g_SioCriticalSection);
    return PIF_ERROR_COM_ERRORS;
}

/* clear the error and purge the receive buffer */
dwError = (DWORD)(~0);                  // set all error code bits on
ClearCommError(hHandle, &dwError, NULL);
PurgeComm( hHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ;

ReadFile()在函式內部包裹著,看起來像:

fResult = ReadFile(hHandle, pBuffer, (DWORD)usBytes, &dwBytesRead, NULL);

if (PifSioCheckPowerDown(usPort, aPifSioTable) == TRUE) {
    return PIF_ERROR_COM_POWER_FAILURE;
}

if (fResult) {
    if (!dwBytesRead) return PIF_ERROR_COM_TIMEOUT;
    return (SHORT)dwBytesRead;
} else {
    SHORT  sErrorCode = 0;     // error code from PifSubGetErrorCode(). must call after GetLastError().
    dwError = GetLastError();
    PifLog (MODULE_PIF_READCOM, LOG_ERROR_PIFSIO_CODE_06);
    PifLog (MODULE_ERROR_NO(MODULE_PIF_READCOM), (USHORT)dwError);
    sErrorCode = PifSubGetErrorCode(hHandle);
    PifLog (MODULE_ERROR_NO(MODULE_PIF_READCOM), (USHORT)abs(sErrorCode));
    PifLog (MODULE_DATA_VALUE(MODULE_PIF_READCOM), usPort);
    return (sErrorCode);
}

uj5u.com熱心網友回復:

我發現了許多涉及管道的類似發布問題,但是使用重疊 I/O 的相同方法也適用。

  • 打破 ReadFile() 阻塞 - 命名管道 (Windows API)
  • Win32 API:讀取檔案超時
  • 設備驅動程式:Windows ReadFile 函式超時

我還在網路上的Peter 博客上找到了以下文章:Getting a handle on usbprint.sys,其中提供了如何為 USB 連接的設備查找 USB 路徑名的代碼和說明。我在下面的課程中使用了一些代碼示例。

我還在 codeproject.com 上找到了由 Chuan-Liang Teng撰寫的 Enumering windows device的文章,其中包含一個列舉連接的 USB 設備并詢問有關設備的各種設定和詳細資訊的示例。那篇文章中的代碼雖然很舊,但對這個特定應用程式來說不是必需的,但很有幫助。

我有一個使用重疊 I/O 的原型 C 類,它似乎正在復制使用 USB 連接到熱敏列印機的串行埠連接所看到的行為。完整的源代碼和 Visual Studio 2017 解決方案和專案檔案位于我的 GitHub 存盤庫https://github.com/RichardChambers/utilities_tools/tree/main/UsbWindows 中,因為此片段具有最相關的部分。

我在銷售點應用程式中使用修改后的代碼做了一個簡單的測驗,現在正在將它集成到現有的熱敏收據列印機源代碼中,該代碼已經與串行埠配合使用。

#include <windows.h>
#include <setupapi.h>
#include <initguid.h>

#include <iostream>    

// This is the GUID for the USB device class.
// It is defined in the include file Usbiodef.h of the Microsoft Windows Driver Kit.
// See also https://msdn.microsoft.com/en-us/library/windows/hardware/ff545972(v=vs.85).aspx which
// provides basic documentation on this GUID.
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE,  0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
        

class UsbSerialDevice
{
public:
    // See https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-server-using-overlapped-i-o?redirectedfrom=MSDN
    // to implement time outs for Write and for Read.
    UsbSerialDevice(const wchar_t* wszVendorIdIn = nullptr);
    ~UsbSerialDevice();
    int CreateEndPoint(const wchar_t* wszVendorId = nullptr, DWORD dwDesiredAccess = (GENERIC_READ | GENERIC_WRITE));
    void CloseEndPoint(void);
    int ListEndPoint(const wchar_t* wszVendorIdIn);
    int ReadStream(void* bString, size_t nBytes);
    int WriteStream(void* bString, size_t nBytes);
    DWORD  SetWriteTimeOut(DWORD msTimeout);
    DWORD  SetReadTimeOut(DWORD msTimeout);

    DWORD     m_dwError;          // GetLastError() for last action
    DWORD     m_dwErrorWrite;     // GetLastError() for last write
    DWORD     m_dwErrorRead;      // GetLastError() for last read
    DWORD     m_dwBytesWritten;   // number of bytes last write
    DWORD     m_dwBytesRead;      // number of bytes last read
    DWORD     m_dwWait;           // WaitForSingleObject() return value

private:
    HANDLE        m_hFile;
    OVERLAPPED    m_oOverlap;
    COMMTIMEOUTS  m_timeOut;
    const unsigned short m_idLen = 255;
    wchar_t  m_wszVendorId[255   1] = { 0 };
};

UsbSerialDevice::UsbSerialDevice(const wchar_t* wszVendorIdIn) :
    m_dwError(0),
    m_dwErrorWrite(0),
    m_dwErrorRead(0),
    m_dwBytesWritten(0),
    m_dwBytesRead(0),
    m_dwWait(0),
    m_hFile(INVALID_HANDLE_VALUE)
{
    memset(&m_oOverlap, 0, sizeof(m_oOverlap));
    m_oOverlap.hEvent = INVALID_HANDLE_VALUE;

    if (wszVendorIdIn != nullptr) ListEndPoint(wszVendorIdIn);
}

void UsbSerialDevice::CloseEndPoint(void )
{
    if (m_hFile && m_hFile != INVALID_HANDLE_VALUE) CloseHandle(m_hFile);
    if (m_oOverlap.hEvent && m_oOverlap.hEvent != INVALID_HANDLE_VALUE) CloseHandle(m_oOverlap.hEvent);
}

UsbSerialDevice::~UsbSerialDevice()
{
    CloseEndPoint();
}


/*
 *  Returns:  -1 - file handle is invalid
 *             0 - write failed. See m_dwErrorWrite for GetLastError() value
 *             1 - write succedded.
*/
int UsbSerialDevice::WriteStream(void* bString, size_t nBytes)
{
    SetLastError(0);
    m_dwError = m_dwErrorWrite = 0;
    m_dwBytesWritten = 0;
    m_dwWait = WAIT_FAILED;

    if (m_hFile && m_hFile != INVALID_HANDLE_VALUE) {

        BOOL  bWrite = WriteFile(m_hFile, bString, nBytes, 0, &m_oOverlap);
        m_dwError = m_dwErrorWrite = GetLastError();

        if (!bWrite && m_dwError == ERROR_IO_PENDING) {

            SetLastError(0);
            m_dwError = m_dwErrorWrite = 0;

            m_dwWait = WaitForSingleObject(m_oOverlap.hEvent, m_timeOut.WriteTotalTimeoutConstant);

            BOOL bCancel = FALSE;

            switch (m_dwWait) {
            case WAIT_OBJECT_0:  // The state of the specified object is signaled.
                break;
            case WAIT_FAILED:    // The function has failed. To get extended error information, call GetLastError.
                m_dwError = m_dwErrorWrite = GetLastError();
                bCancel = CancelIo(m_hFile);
                break;
            case WAIT_TIMEOUT:   // The time-out interval elapsed, and the object's state is nonsignaled.
            case WAIT_ABANDONED: // thread owning mutex terminated before releasing or signaling object.
                bCancel = CancelIo(m_hFile);
                m_dwError = m_dwErrorRead = ERROR_COUNTER_TIMEOUT;
                break;
            }

            bWrite = GetOverlappedResult(m_hFile, &m_oOverlap, &m_dwBytesRead, FALSE);
        }

        return bWrite;  // 0 or FALSE if failed, 1 or TRUE if succeeded.
    }

    return -1;
}

/*
 *  Returns:  -1 - file handle is invalid
 *             0 - read failed. See m_dwErrorRead for GetLastError() value
 *             1 - read succedded.
*/
int UsbSerialDevice::ReadStream(void* bString, size_t nBytes)
{
    SetLastError(0);
    m_dwError = m_dwErrorRead = 0;
    m_dwBytesRead = 0;
    m_dwWait = WAIT_FAILED;

    if (m_hFile && m_hFile != INVALID_HANDLE_VALUE) {

        BOOL  bRead = ReadFile(m_hFile, bString, nBytes, &m_dwBytesRead, &m_oOverlap);
        m_dwError = m_dwErrorRead = GetLastError();

        if (!bRead && m_dwError == ERROR_IO_PENDING) {
            SetLastError(0);
            m_dwError = m_dwErrorRead = 0;

            m_dwWait = WaitForSingleObject(m_oOverlap.hEvent, m_timeOut.ReadTotalTimeoutConstant);

            BOOL bCancel = FALSE;

            switch (m_dwWait) {
            case WAIT_OBJECT_0:  // The state of the specified object is signaled.
                break;
            case WAIT_FAILED:    // The function has failed. To get extended error information, call GetLastError.
                m_dwError = m_dwErrorWrite = GetLastError();
                bCancel = CancelIo(m_hFile);
                break;
            case WAIT_TIMEOUT:   // The time-out interval elapsed, and the object's state is nonsignaled.
            case WAIT_ABANDONED: // thread owning mutex terminated before releasing or signaling object.
                bCancel = CancelIo(m_hFile);
                m_dwError = m_dwErrorRead = ERROR_COUNTER_TIMEOUT;
                break;
            }

            bRead = GetOverlappedResult(m_hFile, &m_oOverlap, &m_dwBytesRead, FALSE);
        }

        return bRead;  // 0 or FALSE if failed, 1 or TRUE if succeeded.
    }

    return -1;
}

int UsbSerialDevice::ListEndPoint(const wchar_t* wszVendorIdIn)
{
    m_dwError = ERROR_INVALID_HANDLE;

    if (wszVendorIdIn == nullptr) return 0;

    HDEVINFO    hDevInfo;

    // we need to make sure the vendor and product id codes are in lower case
    // as this is needed for the CreateFile() function to open the connection
    // to the USB device correctly. this lower case conversion applies to
    // any alphabetic characters in the identifier.
    //
    // for example "VID_0FE6&PID_811E" must be converted to "vid_0fe6&pid_811e"

    wchar_t  wszVendorId[256] = { 0 };

    for (unsigned short i = 0; i < 255 && (wszVendorId[i] = towlower(wszVendorIdIn[i])); i  );

    // We will try to get device information set for all USB devices that have a
    // device interface and are currently present on the system (plugged in).
    hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
    if (hDevInfo != INVALID_HANDLE_VALUE)
    {
        DWORD    dwMemberIdx;
        BOOL     bContinue = TRUE;
        SP_DEVICE_INTERFACE_DATA         DevIntfData;

        // Prepare to enumerate all device interfaces for the device information
        // set that we retrieved with SetupDiGetClassDevs(..)
        DevIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
        dwMemberIdx = 0;

        // Next, we will keep calling this SetupDiEnumDeviceInterfaces(..) until this
        // function causes GetLastError() to return  ERROR_NO_MORE_ITEMS. With each
        // call the dwMemberIdx value needs to be incremented to retrieve the next
        // device interface information.
        for (BOOL bContinue = TRUE; bContinue; ) {
            PSP_DEVICE_INTERFACE_DETAIL_DATA  DevIntfDetailData;
            SP_DEVINFO_DATA    DevData;
            DWORD  dwSize;

            dwMemberIdx  ;
            SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, dwMemberIdx, &DevIntfData);

            if (GetLastError() == ERROR_NO_MORE_ITEMS) break;

            // As a last step we will need to get some more details for each
            // of device interface information we are able to retrieve. This
            // device interface detail gives us the information we need to identify
            // the device (VID/PID), and decide if it's useful to us. It will also
            // provide a DEVINFO_DATA structure which we can use to know the serial
            // port name for a virtual com port.

            DevData.cbSize = sizeof(DevData);

            // Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with
            // a NULL DevIntfDetailData pointer, a DevIntfDetailDataSize
            // of zero, and a valid RequiredSize variable. In response to such a call,
            // this function returns the required buffer size at dwSize.

            SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, NULL, 0, &dwSize, NULL);

            // Allocate memory for the DeviceInterfaceDetail struct. Don't forget to
            // deallocate it later!
            DevIntfDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
            DevIntfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

            if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, DevIntfDetailData, dwSize, &dwSize, &DevData))
            {
                if (wcsstr(DevIntfDetailData->DevicePath, wszVendorId)) {
                    wcscpy_s(m_wszVendorId, DevIntfDetailData->DevicePath);
                }
            }

            HeapFree(GetProcessHeap(), 0, DevIntfDetailData);
        }

        SetupDiDestroyDeviceInfoList(hDevInfo);
    }

    return 0;
}

int UsbSerialDevice::CreateEndPoint(const wchar_t* wszVendorIdIn, DWORD dwDesiredAccess)
{
    if (wszVendorIdIn) {
        ListEndPoint(wszVendorIdIn);
    }

    m_dwError = ERROR_INVALID_HANDLE;

    // Finally we can start checking if we've found a useable device,
    // by inspecting the DevIntfDetailData->DevicePath variable.
    //
    // The DevicePath looks something like this for a Brecknell 67xx Series Serial Scale
    // \\?\usb#vid_1a86&pid_7523#6&28eaabda&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
    //
    // The VID for a particular vendor will be the same for a particular vendor's equipment.
    // The PID is variable for each device of the vendor.
    //
    // As you can see it contains the VID/PID for the device, so we can check
    // for the right VID/PID with string handling routines.

    // See https://github.com/Microsoft/Windows-driver-samples/blob/master/usb/usbview/vndrlist.h

    // See https://blog.peter.skarpetis.com/archives/2005/04/07/getting-a-handle-on-usbprintsys/
    // which describes a sample USB thermal receipt printer test application.

    SetLastError(0);
    m_hFile = CreateFile(m_wszVendorId, dwDesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, 0);
    if (m_hFile == INVALID_HANDLE_VALUE) {
        m_dwError = GetLastError();
//        wprintf(_T("   CreateFile() failed. GetLastError() = %d\n"), m_dwError);
    }
    else {
        m_oOverlap.hEvent = CreateEvent(
            NULL,    // default security attribute 
            TRUE,    // manual-reset event 
            TRUE,    // initial state = signaled 
            NULL);   // unnamed event object 

        m_timeOut.ReadIntervalTimeout = 0;
        m_timeOut.ReadTotalTimeoutMultiplier = 0;
        m_timeOut.ReadTotalTimeoutConstant = 5000;
        m_timeOut.WriteTotalTimeoutMultiplier = 0;
        m_timeOut.WriteTotalTimeoutConstant = 5000;
        m_dwError = 0;   // GetLastError();
        return 1;
    }

    return 0;
}

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

標籤:C 登录 串行端口 USB 读取文件

上一篇:如何使用rundll32.exe在Windows中洗掉檔案?

下一篇:如何在CMFCToolBarFontComboBox上呼叫SetExtendedUI

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

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more