实例介绍
【实例简介】创建TCP服务器,开启连接TCP客户端的线程;将TCP服务器接收的消息发送给各个客户端线程连接的TCP服务器
【实例截图】
【核心代码】
// MainServer.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
#define MAX_LOADSTRING 100
#define MTIMER_ID WM_USER 1
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
// Client Manage Member
#pragma warning(disable:4068)
#pragma warning(disable:4786)
#include<iostream>
#include<string>
#include<map>
using namespace std;
// Main
HWND m_hWnd;
RECT m_Rect;
BOOL m_bShowClient;
BOOL m_bDrawClient;
int m_nPageIndex;
// HDC Member
// Server Function
#pragma comment(lib, "Ws2_32.lib")
#include <stdio.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <process.h>
#define _BUFFER_LENGTH_ 1024
#define _DEFAULT_PORT_ 12345
//数量统计计数
typedef struct _Count_Stru
{
UINT nCientNum;
UINT nRcvThreadNum;
UINT nRcvPagesNum;
UINT nRcvBytesSize;
UINT nRcvAllBytesSize;
}CountStru;
CountStru m_CountInfo;
//数据包结构
typedef struct _PAGEDATA
{
UINT DataNo;
UINT DataSum;
UINT DataOneSize;
UINT DataAllSize;
char DataBuf[1024];
}PAGEDATA;
typedef struct _CLIENT_INFO
{
SOCKADDR_IN mSOCKADDR_IN;
SOCKET mSOCKET;
int nSize;
BOOL bState;
}Client_Info;
map<int,Client_Info> m_ClientMap;
// 服务器状态
typedef struct _SERVER_STATE
{
BOOL bServerState; //服务状态
LONG lHeartNum; //接收心跳数量
LONG lRecvNum; //接收指令数据数量
}Server_State;
Server_State m_ServerState;
//初始化信息
void InitParams(void);
//结束时释放
void FreeParams(void);
//显示信息
void DrawInfo(HDC);
//处理接收信息
void ParseMsg(SOCKET,char*,int);
//接收客户端消息的线程函数
unsigned __stdcall ThreadRecv(LPVOID param)
{
SOCKET sockClient = (SOCKET)param;
int nRecv=0;
UINT nAllSize=0;
int i=0;
map<int,Client_Info>::iterator iter;
char mRcv[1024]={0};
while(SOCKET_ERROR!=nRecv)
{
//按照消息结构接收数据
//ZeroMemory(&mPageData,sizeof(PAGEDATA));
//nRecv=recv(sockClient,(char*)&mPageData,sizeof(PAGEDATA),0);
//一般接收
ZeroMemory(mRcv,1024);
nRecv=recv(sockClient,mRcv,1024,0);
//MessageBox(NULL,"HELLO","ERROR",MB_OK);
if(SOCKET_ERROR == nRecv || 0==nRecv)
{
m_bDrawClient=FALSE;
//关闭Socket
shutdown(sockClient, SD_BOTH);
closesocket(sockClient);
for(i=0,iter=m_ClientMap.begin();iter!=m_ClientMap.end();iter ,i )
{
Client_Info mClientInfo= (Client_Info)iter->second;
if(sockClient==mClientInfo.mSOCKET)
{
//m_ClientMap.erase(iter);
mClientInfo.bState=FALSE;
iter->second=mClientInfo;
//::InvalidateRect(m_hWnd,&m_Rect,FALSE);
//break;
}
}
m_bDrawClient=TRUE;
::InvalidateRect(m_hWnd,&m_Rect,FALSE);
//标记当前线程为有信号
_endthreadex(0);
}
else if(0<nRecv)
{
//处理接收的信息
ParseMsg(sockClient,mRcv,nRecv);
//修改发送人信息
map<int,Client_Info>::iterator iter;
for(iter=m_ClientMap.begin();iter!=m_ClientMap.end();iter )
{
Client_Info mClientInfo= (Client_Info)iter->second;
if(sockClient==mClientInfo.mSOCKET)
{
mClientInfo.nSize=nRecv;
iter->second=mClientInfo;
}
}
::InvalidateRect(m_hWnd,&m_Rect,FALSE);
}
}
return 0;
}
//接受客户端的连接
unsigned __stdcall ThreadAccept(LPVOID param)
{
SOCKET ListenSocket = (SOCKET)param;
while(TRUE)
{
SOCKET sockClient = INVALID_SOCKET;
//printf("start accept...\n");
SOCKADDR_IN addrClient;
int nAddrLen=sizeof(SOCKADDR);
sockClient = accept(ListenSocket, (SOCKADDR*)&addrClient,&nAddrLen);
//sockClient = accept(ListenSocket, NULL,NULL);
if(INVALID_SOCKET == sockClient)
{
//printf("accept failed:%d\n", WSAGetLastError());
}
else
{
m_CountInfo.nCientNum =1;
unsigned threadId;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ThreadRecv,(void*)sockClient, 0, &threadId);
Client_Info mClientInfo;
mClientInfo.nSize=0;
mClientInfo.mSOCKADDR_IN=addrClient;
mClientInfo.mSOCKET=sockClient;
mClientInfo.bState=TRUE;
m_ClientMap.insert(pair<int,Client_Info>(m_CountInfo.nCientNum,mClientInfo));
::InvalidateRect(m_hWnd,&m_Rect,FALSE);
m_CountInfo.nRcvThreadNum =1;
}
}
closesocket(ListenSocket);
WSACleanup();
return 0;
}
int StartServer(void)
{
//Initialize Server Socket Settting
int err;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2,2);
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
return 0;
WSACleanup();
}
// Initialize Server Socket
SOCKET sockSrv=INVALID_SOCKET;
sockSrv=socket(AF_INET,SOCK_STREAM,0);
if(INVALID_SOCKET == sockSrv)
{
//printf("Error at socket(): %d\n", WSAGetLastError());
WSACleanup();
return 0;
}
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(_DEFAULT_PORT_);
// Bind Server Socket
err=bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
if(err == SOCKET_ERROR)
{
//printf("bind failed: %d\n", WSAGetLastError());
closesocket(sockSrv);
WSACleanup();
return 0;
}
// Listen Server Socket
if(listen(sockSrv, SOMAXCONN) == SOCKET_ERROR)
{
//printf("Error at bind():%d \n", WSAGetLastError());
closesocket(sockSrv);
WSACleanup();
return 0;
}
//while(true)
{
unsigned threadId;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ThreadAccept,(void*)sockSrv, 0, &threadId);
m_ServerState.bServerState=TRUE;
//printf("waitting for ClinetSocket to finish...\n");
//WaitForSingleObject(hThread, INFINITE);// 直到线程有信号为止
//CloseHandle(hThread);
}
//WSACleanup();
return 0;
}
int StopServer(void)
{
WSACleanup();
return 0;
}
//
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_MAINSERVER, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MAINSERVER);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_MAINSERVER);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW 1);
wcex.lpszMenuName = (LPCSTR)IDC_MAINSERVER;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
//HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
m_hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW&~WS_MAXIMIZEBOX&~WS_THICKFRAME,
CW_USEDEFAULT, 0, 600, 400, NULL, NULL, hInstance, NULL);
if (!m_hWnd)
{
return FALSE;
}
ShowWindow(m_hWnd, nCmdShow);
InitParams();
UpdateWindow(m_hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
POINT mPt;
//TCHAR szHello[MAX_LOADSTRING];
//LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
char chMsg[100]="";
UINT iDex=0;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
if(IDOK==MessageBox(hWnd,_T("确认要退出服务器程序吗?"),_T("系统提示"),MB_ICONQUESTION|MB_OKCANCEL))
{
DestroyWindow(hWnd);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
DrawInfo(hdc);
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
mPt.x = LOWORD(lParam);
mPt.y = HIWORD(lParam);
if(mPt.x>m_Rect.right-400 && mPt.y>m_Rect.bottom-66)
{
if(mPt.x>m_Rect.right-362 && mPt.x<m_Rect.right-308)
{
m_nPageIndex=0;
//MessageBox(hWnd,"1","ok",MB_OK);
}
if(mPt.x>m_Rect.right-298 && mPt.x<m_Rect.right-244)
{
int nPageCount=0;
if(0==m_ClientMap.size()%48)
{
nPageCount=m_ClientMap.size()/48;
}
else
{
nPageCount=m_ClientMap.size()/48 1;
}
if(m_nPageIndex<nPageCount-1)
{
m_nPageIndex ;
}
//MessageBox(hWnd,"2","ok",MB_OK);
}
if(mPt.x>m_Rect.right-146 && mPt.x<m_Rect.right-90)
{
if(m_nPageIndex>0)
{
m_nPageIndex--;
}
//MessageBox(hWnd,"3","ok",MB_OK);
}
if(mPt.x>m_Rect.right-80 && mPt.x<m_Rect.right-12)
{
int nPageCount=0;
if(0==m_ClientMap.size()%48)
{
nPageCount=m_ClientMap.size()/48;
}
else
{
nPageCount=m_ClientMap.size()/48 1;
}
if(nPageCount>0)
{
m_nPageIndex=nPageCount-1;
}
//MessageBox(hWnd,"4","ok",MB_OK);
}
}
else
{
if(mPt.x>0 && mPt.x<m_Rect.right && mPt.y>26 && mPt.y<52)
{
m_bShowClient=!m_bShowClient;
}
else
{
m_bShowClient=FALSE;
}
}
::InvalidateRect(hWnd,&m_Rect,FALSE);
break;
case WM_LBUTTONUP:
break;
case WM_CLOSE:
if(IDOK==MessageBox(hWnd,_T("确认要退出服务器程序吗?"),_T("系统提示"),MB_ICONQUESTION|MB_OKCANCEL))
{
DestroyWindow(hWnd);
}
case WM_TIMER:
RECT mRect;
mRect.top=4*26 4;
mRect.left=0;
mRect.right=m_Rect.right;
mRect.bottom=5*26 4;
::InvalidateRect(hWnd,&mRect,FALSE);
break;
case WM_DESTROY:
FreeParams();
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
//初始化系统参数
void InitParams(void)
{
m_Rect.top=0;
m_Rect.bottom=400;
m_Rect.left=0;
m_Rect.right=600;
m_CountInfo.nCientNum=0;
m_CountInfo.nRcvPagesNum=0;
m_CountInfo.nRcvThreadNum=0;
m_CountInfo.nRcvBytesSize=0;
m_CountInfo.nRcvAllBytesSize=0;
m_ServerState.lHeartNum=0;
m_ServerState.bServerState=FALSE;
m_ServerState.lRecvNum=0;
m_bShowClient=FALSE;
m_bDrawClient=TRUE;
m_nPageIndex=0;
StartServer();
SetTimer(m_hWnd,MTIMER_ID,1000,NULL);
}
//结束时释放
void FreeParams(void)
{
StopServer();
m_ClientMap.clear();
}
//界面上绘制信息
void DrawInfo(HDC hDC)
{
RECT mRect;
::GetClientRect(m_hWnd,&mRect);
HDC hMemDC=::CreateCompatibleDC(hDC);
HBITMAP hBitMap=::CreateCompatibleBitmap(hDC,mRect.right,mRect.bottom);
HBITMAP hOldBitMap=(HBITMAP)::SelectObject(hMemDC,hBitMap);
::SetTextColor(hMemDC,RGB(192,192,192));
::SetBkColor(hMemDC,RGB(0,0,0));
//::Rectangle(hMemDC,0,0,mRect.right,mRect.bottom);
POINT mPoint;
HPEN hPen=::CreatePen(PS_DOT,1,RGB(100,100,100));
HPEN hOldPen=(HPEN)::SelectObject(hMemDC,hPen);
for(int nY=26;nY<=mRect.bottom;nY =26)
{
::MoveToEx(hMemDC,1,nY,&mPoint);
::LineTo(hMemDC,mRect.right-1,nY);
}
::SelectObject(hMemDC,hOldPen);
::DeleteObject(hPen);
char chMsg[100]="";
mRect.left=2;
mRect.top=4;
sprintf(chMsg,"Server State : %s",m_ServerState.bServerState?"Success(TCP)":"Falied(TCP)");
::DrawText(hMemDC, chMsg, strlen(chMsg), &mRect, DT_LEFT);
mRect.top=1*26 4;
//
map<int,Client_Info>::iterator iter;
int iOnlineClientSize=0;
for(iter=m_ClientMap.begin();iter!=m_ClientMap.end();iter )
{
if(((Client_Info)iter->second).bState)
{
iOnlineClientSize ;
}
else
{
//m_ClientMap.erase(iter);
}
}
//
sprintf(chMsg,"Online Clients Num : %d (Click Me,Look All Client's Info)",iOnlineClientSize);
::DrawText(hMemDC, chMsg, strlen(chMsg), &mRect, DT_LEFT);
mRect.top=2*26 4;
sprintf(chMsg,"Client Heart Jump Num : %d",m_ServerState.lHeartNum);
::DrawText(hMemDC, chMsg, strlen(chMsg), &mRect, DT_LEFT);
mRect.top=3*26 4;
sprintf(chMsg,"Receive Data Page Num : %d",m_ServerState.lRecvNum);
::DrawText(hMemDC, chMsg, strlen(chMsg), &mRect, DT_LEFT);
SYSTEMTIME mSYSTEMTIME;
::GetSystemTime(&mSYSTEMTIME);
mRect.top=4*26 4;
sprintf(chMsg,"Server Datetime : %d-%d-%d %d:%d:%d DayOfWeek : %d",mSYSTEMTIME.wYear,mSYSTEMTIME.wMonth,mSYSTEMTIME.wDay,mSYSTEMTIME.wHour 8,mSYSTEMTIME.wMinute,mSYSTEMTIME.wSecond,mSYSTEMTIME.wDayOfWeek);
::DrawText(hMemDC, chMsg, strlen(chMsg), &mRect, DT_LEFT);
if(m_bShowClient)
{
HBRUSH hBru=::CreateSolidBrush(RGB(253,251,183));
HBRUSH hOldBru=(HBRUSH)::SelectObject(hMemDC,hBru);
::Rectangle(hMemDC,0,52,m_Rect.right,m_Rect.bottom);
::SelectObject(hMemDC,hOldBru);
::DeleteObject(hBru);
//map<int,Client_Info>::iterator iter;
RECT mNetInfoRect;
mNetInfoRect.left=2;
mNetInfoRect.top=52;
mNetInfoRect.right=m_Rect.right;
mNetInfoRect.bottom=m_Rect.bottom;
SetBkMode(hMemDC,TRANSPARENT);
//SetTextColor(hMemDC,RGB(0,0,0));
if(m_bDrawClient)
{
int iIndex=0;
int iTmpIndex=0;
for(iIndex=0,iter=m_ClientMap.begin();iter!=m_ClientMap.end();iter )
{
if(iTmpIndex<m_nPageIndex*48)
{
iTmpIndex ;
continue;
}
if(((Client_Info)iter->second).bState)
{
::SetTextColor(hMemDC,RGB(0,0,255));
/*if(iIndex<16)
{
mNetInfoRect.top=iIndex*18 52;
mNetInfoRect.left=2;
}
if(iIndex<32 && iIndex>=16)
{
mNetInfoRect.top=(iIndex%16)*18 52;
mNetInfoRect.left=200;
}
if(iIndex<48 && iIndex>=32)
{
mNetInfoRect.top=(iIndex%32)*18 52;
mNetInfoRect.left=400;
}
if(iIndex<48)
{
Client_Info mClientInfo= (Client_Info)iter->second;
sprintf(chMsg,"NetAdress: %s:%d",inet_ntoa(mClientInfo.mSOCKADDR_IN.sin_addr),mClientInfo.mSOCKADDR_IN.sin_port);
::DrawText(hMemDC, chMsg, strlen(chMsg), &mNetInfoRect, DT_LEFT);
}
iIndex ;*/
}
else
{
::SetTextColor(hMemDC,RGB(255,0,0));
}
if(iIndex<16)
{
mNetInfoRect.top=iIndex*18 52;
mNetInfoRect.left=2;
}
if(iIndex<32 && iIndex>=16)
{
mNetInfoRect.top=(iIndex%16)*18 52;
mNetInfoRect.left=200;
}
if(iIndex<48 && iIndex>=32)
{
mNetInfoRect.top=(iIndex%32)*18 52;
mNetInfoRect.left=400;
}
if(iIndex<48)
{
Client_Info mClientInfo= (Client_Info)iter->second;
sprintf(chMsg,"NetAdress: %s:%d",inet_ntoa(mClientInfo.mSOCKADDR_IN.sin_addr),mClientInfo.mSOCKADDR_IN.sin_port);
::DrawText(hMemDC, chMsg, strlen(chMsg), &mNetInfoRect, DT_LEFT);
}
iIndex ;
}
::SetTextColor(hMemDC,RGB(0,0,0));
::SetBkMode(hMemDC,OPAQUE);
::SetBkColor(hMemDC,RGB(200,200,200));
RECT mRectOpt;
mRectOpt.left=mNetInfoRect.right-80;
mRectOpt.top=mNetInfoRect.bottom-62;
mRectOpt.right=mNetInfoRect.right;
mRectOpt.bottom=mNetInfoRect.bottom;
::DrawText(hMemDC, "[最后一页]", 10, &mRectOpt, DT_LEFT);
mRectOpt.left=mRectOpt.left-64;
::DrawText(hMemDC, "[上一页]", 8, &mRectOpt, DT_LEFT);
mRectOpt.left=mRectOpt.left-64;
if(0==m_ClientMap.size())
{
sprintf(chMsg,"%d/%d",0,0);
}
else
{
int nPageCount=0;
if(0==m_ClientMap.size()%48)
{
nPageCount=m_ClientMap.size()/48;
}
else
{
nPageCount=m_ClientMap.size()/48 1;
}
sprintf(chMsg,"%d/%d",m_nPageIndex 1,nPageCount);
}
::DrawText(hMemDC, chMsg, strlen(chMsg), &mRectOpt, DT_LEFT);
mRectOpt.left=mRectOpt.left-90;
::DrawText(hMemDC, "[下一页]", 8, &mRectOpt, DT_LEFT);
mRectOpt.left=mRectOpt.left-64;
::DrawText(hMemDC, "[第一页]", 8, &mRectOpt, DT_LEFT);
}
}
::BitBlt(hDC,0,0,mRect.right,mRect.bottom,hMemDC,0,0,SRCCOPY);
::SelectObject(hMemDC,hOldBitMap);
::DeleteObject(hBitMap);
::DeleteDC(hMemDC);
}
//处理接收信息
void ParseMsg(SOCKET mSendSocket,char* mCh,int nRcvLen)
{
if(('&'==mCh[0] && '^'==mCh[6]) || (nRcvLen<10 && '^'==mCh[nRcvLen-1]))
{
//&c0001^ 心跳
m_ServerState.lHeartNum ;
//send(mSendSocket,"&s0001^",7,0);
}
else
{
m_ServerState.lRecvNum ;
map<int,Client_Info>::iterator iter;
for(iter=m_ClientMap.begin();iter!=m_ClientMap.end();iter )
{
Client_Info mClientInfo= (Client_Info)iter->second;
if(mSendSocket!=mClientInfo.mSOCKET && mClientInfo.bState)
{
send(mClientInfo.mSOCKET,mCh,nRcvLen,0);//
}
}
}
}
好例子网口号:伸出你的我的手 — 分享!
相关软件
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


网友评论
我要评论