中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

C++實現(xiàn)ping功能的代碼

2018-07-20    來源:open-open

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用
/*
 * COPYRIGHT:   See COPYING in the top level directory
 * PROJECT:     ReactOS ping utility
 * FILE:        base/applications/network/ping/ping.c
 * PURPOSE:     Network test utility
 * PROGRAMMERS:
 */

#include <winsock2.h>
#include <ws2tcpip.h>
#include <tchar.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#pragma comment( lib, "ws2_32.lib" )  
#define ULONG_MAX 0xffffffffUL

/* General ICMP constants */
#define ICMP_MINSIZE        8     /* Minimum ICMP packet size */
#define ICMP_MAXSIZE        65535 /* Maximum ICMP packet size */

/* ICMP message types */
#define ICMPMSG_ECHOREQUEST 8     /* ICMP ECHO request message */
#define ICMPMSG_ECHOREPLY   0     /* ICMP ECHO reply message */

#pragma pack(4)

/* IPv4 header structure */
typedef struct _IPv4_HEADER
{
    unsigned char IHL:4;
    unsigned char Version:4;
    unsigned char TOS;
    unsigned short Length;
    unsigned short Id;
    unsigned short FragFlags;
    unsigned char TTL;
    unsigned char Protocol;
    unsigned short Checksum;
    unsigned int SrcAddress;
    unsigned int DstAddress;
} IPv4_HEADER, *PIPv4_HEADER;

/* ICMP echo request/reply header structure */
typedef struct _ICMP_HEADER
{
    unsigned char Type;
    unsigned char Code;
    unsigned short Checksum;
    unsigned short Id;
    unsigned short SeqNum;
} ICMP_HEADER, *PICMP_HEADER;

typedef struct _ICMP_ECHO_PACKET
{
    ICMP_HEADER Icmp;
} ICMP_ECHO_PACKET, *PICMP_ECHO_PACKET;

#pragma pack(1)

BOOL                NeverStop;
BOOL                ResolveAddresses;
UINT                PingCount;
UINT                DataSize;   /* ICMP echo request data size */
BOOL                DontFragment;
ULONG               TTLValue;
ULONG               TOSValue;
ULONG               Timeout;
WCHAR               TargetName[256];
SOCKET              IcmpSock;
SOCKADDR_IN         Target;
WCHAR               TargetIP[16];
FD_SET              Fds;
TIMEVAL             Timeval;
UINT                CurrentSeqNum;
UINT                SentCount;
UINT                LostCount;
BOOL                MinRTTSet;
LARGE_INTEGER       MinRTT;     /* Minimum round trip time in microseconds */
LARGE_INTEGER       MaxRTT;
LARGE_INTEGER       SumRTT;
LARGE_INTEGER       AvgRTT;
LARGE_INTEGER       TicksPerMs; /* Ticks per millisecond */
LARGE_INTEGER       TicksPerUs; /* Ticks per microsecond */
LARGE_INTEGER       SentTime;
BOOL                UsePerformanceCounter;
HANDLE              hStdOutput;

#ifndef NDEBUG
/* Display the contents of a buffer */
static VOID DisplayBuffer(
    PVOID Buffer,
    DWORD Size)
{
    UINT i;
    PCHAR p;

    printf("Buffer (0x%p)  Size (0x%lX).\n", Buffer, Size);

    p = (PCHAR)Buffer;
    for (i = 0; i < Size; i++)
    {
        if (i % 16 == 0)
            printf("\n");
        printf("%02X ", (p[i]) & 0xFF);
    }
}
#endif /* !NDEBUG */

/* Display usage information on screen */
static VOID Usage(VOID)
{
    printf("用法:ping [-t] [-n 次數(shù)] [-l 大小] [-w 超時] 目標主機\n\n\
選項:\n\
    -t             不停呼叫指定的主機直到被終止。\n\
                   要停止 - 按下 Ctrl-C。\n\
    -n 次數(shù)         發(fā)送回響包的次數(shù)。\n\
    -l 大小         發(fā)送包的大小。\n\
    -w 超時         等待每個回復的時間(毫秒)。\n\n\0");
}

/* Reset configuration to default values */
static VOID Reset(VOID)
{
    LARGE_INTEGER PerformanceCounterFrequency;

    NeverStop             = FALSE;
    ResolveAddresses      = FALSE;
    PingCount             = 4;
    DataSize              = 32;
    DontFragment          = FALSE;
    TTLValue              = 128;
    TOSValue              = 0;
    Timeout               = 1000;
    UsePerformanceCounter = QueryPerformanceFrequency(&PerformanceCounterFrequency);

    if (UsePerformanceCounter)
    {
        /* Performance counters may return incorrect results on some multiprocessor
           platforms so we restrict execution on the first processor. This may fail
           on Windows NT so we fall back to GetCurrentTick() for timing */
        if (SetThreadAffinityMask (GetCurrentThread(), 1) == 0)
            UsePerformanceCounter = FALSE;

        /* Convert frequency to ticks per millisecond */
        TicksPerMs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000;
        /* And to ticks per microsecond */
        TicksPerUs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000000;
    }
    if (!UsePerformanceCounter)
    {
        /* 1 tick per millisecond for GetCurrentTick() */
        TicksPerMs.QuadPart = 1;
        /* GetCurrentTick() cannot handle microseconds */
        TicksPerUs.QuadPart = 1;
    }
}
/*
 * Convert a unicode string to an unsigned long integer.
 *
 * Ignores `locale' stuff.  Assumes that the upper and lower case
 * alphabets and digits are each contiguous.
 *
 * @implemented
 */
unsigned long
wcstoul(const wchar_t *nptr, wchar_t **endptr, int base)
{
  const wchar_t *s = nptr;
  unsigned long acc;
  int c;
  unsigned long cutoff;
  int neg = 0, any, cutlim;

  /*
   * See strtol for comments as to the logic used.
   */
  do {
    c = *s++;
  } while (iswctype(c, _SPACE));
  if (c == L'-')
  {
    neg = 1;
    c = *s++;
  }
  else if (c == L'+')
    c = *s++;
  if ((base == 0 || base == 16) &&
      c == L'0' && (*s == L'x' || *s == L'X'))
  {
    c = s[1];
    s += 2;
    base = 16;
  }
  if (base == 0)
    base = c == L'0' ? 8 : 10;
  cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
  cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
  for (acc = 0, any = 0;; c = *s++)
  {
    if (iswctype(c, _DIGIT))
      c -= L'0';
    else if (iswctype(c, _ALPHA))
      c -= iswctype(c, _UPPER) ? L'A' - 10 : L'a' - 10;
    else
      break;
    if (c >= base)
      break;
    if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
      any = -1;
    else {
      any = 1;
      acc *= base;
      acc += c;
    }
  }
  if (any < 0)
  {
    acc = ULONG_MAX;
  }
  else if (neg)
    acc = 0-acc;
  if (endptr != 0)
    *endptr = any ? (wchar_t *)((size_t)(s - 1)) : (wchar_t *)((size_t)nptr);
  return acc;
}
/* Parse command line parameters */
static BOOL ParseCmdline(int argc, LPWSTR argv[])
{
    INT i;
    BOOL FoundTarget = FALSE, InvalidOption = FALSE;

    if (argc < 2)
    {
        Usage();
        return FALSE;
    }

    for (i = 1; i < argc; i++)
    {
        if (argv[i][0] == L'-' || argv[i][0] == L'/')
        {
            switch (argv[i][1])
            {
                case L't': NeverStop = TRUE; break;
                case L'a': ResolveAddresses = TRUE; break;
                case L'n':
                    if (i + 1 < argc)
                        PingCount = wcstoul(argv[++i], NULL, 0);
                    else
                        InvalidOption = TRUE;
                    break;
                case L'l':
                    if (i + 1 < argc)
                    {
                        DataSize = wcstoul(argv[++i], NULL, 0);

                        if (DataSize > ICMP_MAXSIZE - sizeof(ICMP_ECHO_PACKET) - sizeof(IPv4_HEADER))
                        {
                            printf("-l 選項的值無效,有效的范圍是從 0 到 %1!d!。\n\0",ICMP_MAXSIZE - \
                                         (int)sizeof(ICMP_ECHO_PACKET) - \
                                         (int)sizeof(IPv4_HEADER));
                            return FALSE;
                        }
                    } else
                        InvalidOption = TRUE;
                    break;
                case L'f': DontFragment = TRUE; break;
                case L'i':
                    if (i + 1 < argc)
                        TTLValue = wcstoul(argv[++i], NULL, 0);
                    else
                        InvalidOption = TRUE;
                    break;
                case L'v':
                    if (i + 1 < argc)
                        TOSValue = wcstoul(argv[++i], NULL, 0);
                    else
                        InvalidOption = TRUE;
                    break;
                case L'w':
                    if (i + 1 < argc)
                        Timeout = wcstoul(argv[++i], NULL, 0);
                    else
                        InvalidOption = TRUE;
                    break;
                case '?':
                    Usage();
                    return FALSE;
                default:
                    printf("錯誤選項 %1。\n\0", argv[i]);
                    return FALSE;
            }
            if (InvalidOption)
            {
                printf("錯誤選項格式 %1。\n\0", argv[i]);
                return FALSE;
            }
        }
        else
        {
            if (FoundTarget)
            {
                printf("錯誤參數(shù) %1。\n\0", argv[i]);
                return FALSE;
            }
            else
            {
                wcscpy(TargetName, argv[i]);
                FoundTarget = TRUE;
            }
        }
    }

    if (!FoundTarget)
    {
        printf("目標主機的名稱或 IP 地址必須被指定。\n\0");
        return FALSE;
    }

    return TRUE;
}

/* Calculate checksum of data */
static WORD Checksum(PUSHORT data, UINT size)
{
    ULONG sum = 0;

    while (size > 1)
    {
        sum  += *data++;
        size -= sizeof(USHORT);
    }

    if (size)
        sum += *(UCHAR*)data;

    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);

    return (USHORT)(~sum);
}

/* Prepare to ping target */
static BOOL Setup(VOID)
{
    WORD     wVersionRequested;
    WSADATA  WsaData;
    INT      Status;
    ULONG    Addr;
    PHOSTENT phe;
    CHAR     aTargetName[256];

    wVersionRequested = MAKEWORD(2, 2);

    Status = WSAStartup(wVersionRequested, &WsaData);
    if (Status != 0)
    {
        printf("不能初始化 winsock dll。\n\0");
        return FALSE;
    }

    IcmpSock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0);
    if (IcmpSock == INVALID_SOCKET)
    {
        printf("不能創(chuàng)建套接字 (#%1!d!)。\n\0", WSAGetLastError());
        return FALSE;
    }

    if (setsockopt(IcmpSock,
                   IPPROTO_IP,
                   IP_DONTFRAGMENT,
                   (const char *)&DontFragment,
                   sizeof(DontFragment)) == SOCKET_ERROR)
    {
        printf("setsockopt 失敗 (%1!d!)。\n\0", WSAGetLastError());
        return FALSE;
    }

    if (setsockopt(IcmpSock,
                   IPPROTO_IP,
                   IP_TTL,
                   (const char *)&TTLValue,
                   sizeof(TTLValue)) == SOCKET_ERROR)
    {
        printf("setsockopt 失敗 (%1!d!)。\n\0", WSAGetLastError());
        return FALSE;
    }

    if(!WideCharToMultiByte(CP_ACP, 0, TargetName, -1, aTargetName,\
                            sizeof(aTargetName), NULL, NULL))
    {
        printf("未知主機 %1。\n\0", TargetName);
        return FALSE;
    }

    ZeroMemory(&Target, sizeof(Target));
    phe = NULL;
    Addr = inet_addr(aTargetName);
    if (Addr == INADDR_NONE)
    {
        phe = gethostbyname(aTargetName);
        if (phe == NULL)
        {
            printf("未知主機 %1。\n\0", TargetName);
            return FALSE;
        }

        CopyMemory(&Target.sin_addr, phe->h_addr, phe->h_length);
        Target.sin_family = phe->h_addrtype;
    }
    else
    {
        Target.sin_addr.s_addr = Addr;
        Target.sin_family = AF_INET;
    }

    swprintf(TargetIP, L"%d.%d.%d.%d", Target.sin_addr.S_un.S_un_b.s_b1,\
                                       Target.sin_addr.S_un.S_un_b.s_b2,\
                                       Target.sin_addr.S_un.S_un_b.s_b3,\
                                       Target.sin_addr.S_un.S_un_b.s_b4);
    CurrentSeqNum = 1;
    SentCount = 0;
    LostCount = 0;
    MinRTT.QuadPart = 0;
    MaxRTT.QuadPart = 0;
    SumRTT.QuadPart = 0;
    MinRTTSet       = FALSE;
    return TRUE;
}

/* Close socket */
static VOID Cleanup(VOID)
{
    if (IcmpSock != INVALID_SOCKET)
        closesocket(IcmpSock);

    WSACleanup();
}

static VOID QueryTime(PLARGE_INTEGER Time)
{
    if (UsePerformanceCounter)
    {
        if (QueryPerformanceCounter(Time) == 0)
        {
            /* This should not happen, but we fall
               back to GetCurrentTick() if it does */
            Time->u.LowPart  = (ULONG)GetTickCount();
            Time->u.HighPart = 0;

            /* 1 tick per millisecond for GetCurrentTick() */
            TicksPerMs.QuadPart = 1;
            /* GetCurrentTick() cannot handle microseconds */
            TicksPerUs.QuadPart = 1;

            UsePerformanceCounter = FALSE;
        }
    }
    else
    {
        Time->u.LowPart  = (ULONG)GetTickCount();
        Time->u.HighPart = 0;
    }
}
/*
 * @implemented
 */
wchar_t *
_i64tow(__int64 value, wchar_t *string, int radix)
{
    ULONGLONG val;
    int negative;
    WCHAR buffer[65];
    PWCHAR pos;
    WCHAR digit;

    if (value < 0 && radix == 10) {
    negative = 1;
        val = -value;
    } else {
    negative = 0;
        val = value;
    } /* if */

    pos = &buffer[64];
    *pos = '\0';

    do {
    digit = (WCHAR)(val % radix);
    val = val / radix;
    if (digit < 10) {
        *--pos = '0' + digit;
    } else {
        *--pos = 'a' + digit - 10;
    } /* if */
    } while (val != 0L);

    if (negative) {
    *--pos = '-';
    } /* if */

    if (string != NULL) {
    memcpy(string, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR));
    } /* if */
    return string;
}

static VOID TimeToMsString(LPWSTR String, LARGE_INTEGER Time)
{
    WCHAR         Convstr[40];
    LARGE_INTEGER LargeTime;

    LargeTime.QuadPart = Time.QuadPart / TicksPerMs.QuadPart;

    _i64tow(LargeTime.QuadPart, Convstr, 10);
    wcscpy(String, Convstr);
    wcscat(String, L"ms\0");
}

/* Locate the ICMP data and print it. Returns TRUE if the packet was good,
   FALSE if not */
static BOOL DecodeResponse(PCHAR buffer, UINT size, PSOCKADDR_IN from)
{
    PIPv4_HEADER      IpHeader;
    PICMP_ECHO_PACKET Icmp;
    UINT              IphLength;
    WCHAR             Time[100];
    LARGE_INTEGER     RelativeTime;
    LARGE_INTEGER     LargeTime;
    WCHAR             Sign[2];
    WCHAR wfromIP[16];

    IpHeader = (PIPv4_HEADER)buffer;

    IphLength = IpHeader->IHL * 4;

    if (size  < IphLength + ICMP_MINSIZE)
    {
#ifndef NDEBUG
        printf("Bad size (0x%X < 0x%X)\n", size, IphLength + ICMP_MINSIZE);
#endif /* !NDEBUG */
        return FALSE;
    }

    Icmp = (PICMP_ECHO_PACKET)(buffer + IphLength);

    if (Icmp->Icmp.Type != ICMPMSG_ECHOREPLY)
    {
#ifndef NDEBUG
        printf("Bad ICMP type (0x%X should be 0x%X)\n", Icmp->Icmp.Type, ICMPMSG_ECHOREPLY);
#endif /* !NDEBUG */
        return FALSE;
    }

    if (Icmp->Icmp.Id != (USHORT)GetCurrentProcessId())
    {
#ifndef NDEBUG
        printf("Bad ICMP id (0x%X should be 0x%X)\n", Icmp->Icmp.Id, (USHORT)GetCurrentProcessId());
#endif /* !NDEBUG */
        return FALSE;
    }

    if (from->sin_addr.s_addr != Target.sin_addr.s_addr)
    {
#ifndef NDEBUG
        printf("Bad source address (%s should be %s)\n", inet_ntoa(from->sin_addr), inet_ntoa(Target.sin_addr));
#endif /* !NDEBUG */
        return FALSE;
    }

    QueryTime(&LargeTime);

    RelativeTime.QuadPart = (LargeTime.QuadPart - SentTime.QuadPart);

    if ((RelativeTime.QuadPart / TicksPerMs.QuadPart) < 1)
    {

        wcscpy(Sign, L"<");
        wcscpy(Time, L"1ms\0");
    }
    else
    {
        wcscpy(Sign, L"=");
        TimeToMsString(Time, RelativeTime);
    }

    swprintf(wfromIP, L"%d.%d.%d.%d", from->sin_addr.S_un.S_un_b.s_b1,\
                                      from->sin_addr.S_un.S_un_b.s_b2,\
                                      from->sin_addr.S_un.S_un_b.s_b3,\
                                      from->sin_addr.S_un.S_un_b.s_b4);
    printf("來自 %1 的回復:字節(jié)數(shù)=%2!d! 時間%3%4 TTL=%5!d!\n\0", wfromIP,\
                 size - IphLength - (int)sizeof(ICMP_ECHO_PACKET),\
                 Sign, Time, IpHeader->TTL);

    if (RelativeTime.QuadPart < MinRTT.QuadPart || !MinRTTSet)
    {
        MinRTT.QuadPart = RelativeTime.QuadPart;
        MinRTTSet = TRUE;
    }
    if (RelativeTime.QuadPart > MaxRTT.QuadPart)
        MaxRTT.QuadPart = RelativeTime.QuadPart;

    SumRTT.QuadPart += RelativeTime.QuadPart;

    return TRUE;
}

/* Send and receive one ping */
static BOOL Ping(VOID)
{
    INT                 Status;
    SOCKADDR            From;
    INT                 Length;
    PVOID               Buffer;
    UINT                Size;
    PICMP_ECHO_PACKET   Packet;

    /* Account for extra space for IP header when packet is received */
    Size   = DataSize + 128;
    Buffer = GlobalAlloc(0, Size);
    if (!Buffer)
    {
        printf("空閑資源不足。\n\0");
        return FALSE;
    }

    ZeroMemory(Buffer, Size);
    Packet = (PICMP_ECHO_PACKET)Buffer;

    /* Assemble ICMP echo request packet */
    Packet->Icmp.Type     = ICMPMSG_ECHOREQUEST;
    Packet->Icmp.Code     = 0;
    Packet->Icmp.Id       = (USHORT)GetCurrentProcessId();
    Packet->Icmp.SeqNum   = htons((USHORT)CurrentSeqNum);
    Packet->Icmp.Checksum = 0;

    /* Calculate checksum for ICMP header and data area */
    Packet->Icmp.Checksum = Checksum((PUSHORT)&Packet->Icmp, sizeof(ICMP_ECHO_PACKET) + DataSize);

    CurrentSeqNum++;

    /* Send ICMP echo request */

    FD_ZERO(&Fds);
    FD_SET(IcmpSock, &Fds);
    Timeval.tv_sec  = Timeout / 1000;
    Timeval.tv_usec = Timeout % 1000;
    Status = select(0, NULL, &Fds, NULL, &Timeval);
    if ((Status != SOCKET_ERROR) && (Status != 0))
    {

#ifndef NDEBUG
        printf("Sending packet\n");
        DisplayBuffer(Buffer, sizeof(ICMP_ECHO_PACKET) + DataSize);
        printf("\n");
#endif /* !NDEBUG */

        Status = sendto(IcmpSock, (const char *)Buffer, sizeof(ICMP_ECHO_PACKET) + DataSize,
            0, (SOCKADDR*)&Target, sizeof(Target));
        QueryTime(&SentTime);
        SentCount++;
    }
    if (Status == SOCKET_ERROR)
    {
        if (WSAGetLastError() == WSAEHOSTUNREACH)
            printf("目標主機不可到達。\n\0");
        else
            printf("無法發(fā)送數(shù)據(jù) (%1!d!)。\n\0", WSAGetLastError());
        GlobalFree(Buffer);
        return FALSE;
    }

    /* Expect to receive ICMP echo reply */
    FD_ZERO(&Fds);
    FD_SET(IcmpSock, &Fds);
    Timeval.tv_sec  = Timeout / 1000;
    Timeval.tv_usec = Timeout % 1000;

    do {
        Status = select(0, &Fds, NULL, NULL, &Timeval);
        if ((Status != SOCKET_ERROR) && (Status != 0))
        {
            Length = sizeof(From);
            Status = recvfrom(IcmpSock, (char *)Buffer, Size, 0, &From, &Length);

#ifndef NDEBUG
            printf("Received packet\n");
            DisplayBuffer(Buffer, Status);
            printf("\n");
#endif /* !NDEBUG */
        }
        else
            LostCount++;
        if (Status == SOCKET_ERROR)
        {
            if (WSAGetLastError() != WSAETIMEDOUT)
            {
                printf("無法接收數(shù)據(jù) (%1!d!)。\n\0", WSAGetLastError());
                GlobalFree(Buffer);
                return FALSE;
            }
            Status = 0;
        }

        if (Status == 0)
        {
            printf("請求超時。\n\0");
            GlobalFree(Buffer);
            return TRUE;
        }

    } while (!DecodeResponse((char*)Buffer, Status, (PSOCKADDR_IN)&From));

    GlobalFree(Buffer);
    return TRUE;
}

/* Program entry point */
int wmain(int argc, LPWSTR argv[])
{
    UINT Count;
    WCHAR MinTime[20];
    WCHAR MaxTime[20];
    WCHAR AvgTime[20];

    hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);

    Reset();

    if ((ParseCmdline(argc, argv)) && (Setup()))
    {

        printf("\n正在呼叫 %1 [%2] ,數(shù)據(jù)包大小 %3!d! 字節(jié):\n\n\0", TargetName, TargetIP, DataSize);

        Count = 0;
        while ((NeverStop) || (Count < PingCount))
        {
            Ping();
            Count++;
            if((NeverStop) || (Count < PingCount))
                Sleep(Timeout);
        };

        Cleanup();

        /* Calculate avarage round trip time */
        if ((SentCount - LostCount) > 0)
            AvgRTT.QuadPart = SumRTT.QuadPart / (SentCount - LostCount);
        else
            AvgRTT.QuadPart = 0;

        /* Calculate loss percent */
        Count = SentCount ? (LostCount * 100) / SentCount : 0;

        if (!MinRTTSet)
            MinRTT = MaxRTT;

        TimeToMsString(MinTime, MinRTT);
        TimeToMsString(MaxTime, MaxRTT);
        TimeToMsString(AvgTime, AvgRTT);

        /* Print statistics */
        printf("\n%1 的呼叫統(tǒng)計:\n\0", TargetIP);
        printf("    數(shù)據(jù)包:發(fā)送個數(shù) = %1!d!,接收個數(shù) = %2!d!,丟失個數(shù) = %3!d! (丟失率 %4!d!%%),\n\0",\
                     SentCount, SentCount - LostCount, LostCount, Count);

        /* Print approximate times or NO approximate times if 100% loss */
        if ((SentCount - LostCount) > 0)
        {
            printf("近似來回所需時間(毫秒):\n\0");
            printf("    最小值 = %1, 最大值 = %2, 平均值 = %3\n\0", MinTime, MaxTime, AvgTime);
        }
    }
    else
    {
        return 1;
    }
    return 0;
}

/* EOF */

標簽: isp

版權申明:本站文章部分自網(wǎng)絡,如有侵權,請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:php過濾html標簽

下一篇:PHP去除多余空格 多個連續(xù)空格只保留一個