高级Socket编程技术
高级Socket编程技术
实验目的
1.了解阻塞与非阻塞模式Socket编程的工作原理。
2.了解Socket编程的5种模型的工作原理和使用方法。
3.掌握Select模型和WSAAsyncSelect模型的网络应用程序编程。
二、实验内容
1.参考教材编写工作于非阻塞模式的多线程TCP服务器应用程序和工作于非阻塞模式客户端应用程序,并进行数据收发测试。
2.编写基于WSAAsyncSelect模型、工作于并发方式的基于对话框的TCP服务器程序和客户端程序,并进行数据收发测试。
基于WSAAsyncSelect模型的服务器程序
基于WSAAsyncSelect模型的客户端程序
要求:(1)客户端程序和服务器端程序之间都能够多次发送消息给对方,也能够多次接收对方发送的消息。(2)将上述1小题的全部代码附在附录上,将2小题源代码打包和实验报告一并提交。
三、实验原理
1.非阻塞模式
概念
Ioctlsocket
函数功能是控制套接口的模式,可用于任一状态的任一套接口,可以调用次函数来讲Socket设置为非阻塞模式。
CreateThread函数
用于创建于一个专门的通信线程,实现多客户端通信。
WSAEWOULDBLOCK
Winsock异常 WSAEWOULDBLOCK说明Output Buffer 已经满了,无法再写入数据
2. WSAAsyncSelect模型工作原理
WSAAsyncSelect模型是Windows Sockets的一个异步I/O模型。应用程序可以用它在一个套接字上接收以Windows消息为基础的网络事件。应用程序创建套接字后,调用WSAAsyncSelect()函数注册感兴趣的网络事件,当事件发生时,windows窗口接收到消息,然后程序就可以对收到的网络事件进行处理。WSAAsyncSelect模型是非阻塞的。应用程序在调用recv()函数接收数据之前,调用WSAAsyncSelect()函数注册网络事件。WSAAsyncSelect()函数立即返回,线程继续运行。当系统中数据准备好时,向应用程序发送消息。程序接收到消息后调用recv()函数接收数据。
WSAAsyncSelect函数编程方法步骤
1)初始化套接字相关信息:
(2)开始启动一个事件通知。WSAAsyncSelect(Sock,hWnd,自定义消息,网络事件)
(3)响应窗口的自定义消息处理函数,其中lparam的高位字包含了可能出现的错误
代码,低字节表示发生的网络事件。wParam表示发生网络事件的套接字。
WSAGETSELECTERROR(lParam);查看是否出现错误,获取低字节位
WSAGETSELECTEVENT(lParam);查看发生了什么事件,获取高字节位
事件种类请查看MSDN,可用WSAGetLastError()来获取错误信息。
四、实验步骤
1.非阻塞模式下的客服端和服务器端信息的收发测试,如图,客户端1在1588端口上向服务器端发送数据,客户端2在3124端口上向服务器端发送数据。处于非阻塞状态。
- 基于WSAAsyncSelect模型、工作于并发方式的基于对话框的TCP服务器程序和客户端程序,并进行数据收发测试。
五、实验小结
附:程序源代码
服务器(窗口)
#include "stdafx.h"
#include "Exp07_AsyncServer.h"#include<WINSOCK2.h>
#pragma comment(lib,"ws2_32.lib")#define MAX_LOADSTRING 100#define WM_SOCKET WM_USER+0x10 //①自定义socket消息// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名SOCKET sockSer,sockConn; //服务器端要创建两个套接字
SOCKADDR_IN addrSer, addrCli;
int len =sizeof(SOCKADDR);
char sendbuf[256],recvbuf[256];
char clibuf[999]="客户端: >",serbuf[999]="服务器: >";// 此代码模块中包含的函数的前向声明:
BOOL InitInstance(HINSTANCE, int);
INT_PTR CALLBACK AsyncSrvProc(HWND, UINT, WPARAM, LPARAM);int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPTSTR lpCmdLine,_In_ int nCmdShow)
{UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);// TODO: 在此放置代码。MSG msg;HACCEL hAccelTable;// 初始化全局字符串LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadString(hInstance, IDC_EXP07_ASYNCSERVER, szWindowClass, MAX_LOADSTRING);// 执行应用程序初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_EXP07_ASYNCSERVER));// 主消息循环:while (GetMessage(&msg, NULL, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}return (int) msg.wParam;
}//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{HWND hWnd;hInst = hInstance; // 将实例句柄存储在全局变量中hWnd =CreateDialog(hInstance, MAKEINTRESOURCE(IDD_SERVER), GetDesktopWindow(), AsyncSrvProc);if (!hWnd){return FALSE;}ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return TRUE;
}// “关于”框的消息处理程序。
INT_PTR CALLBACK AsyncSrvProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{UNREFERENCED_PARAMETER(lParam);char ip[16],port[5]; switch (message){case WM_INITDIALOG:SetDlgItemText(hDlg,IDC_IP,"127.0.0.1"); //设置ip文本框的内容SetDlgItemText(hDlg,IDC_PORT,"5566"); //设置端口文本框的内容WSADATA wsaData;if(WSAStartup(MAKEWORD(2,2), &wsaData)) {MessageBox(hDlg,"Winsock加载失败","警告",0);WSACleanup();return (INT_PTR)TRUE;}case WM_SOCKET: //三:自定义消息 if(WSAGETSELECTERROR(lParam)){MessageBoxA(NULL, "Socket错误", "tip", 0); }else{switch (WSAGETSELECTEVENT(lParam)) { //选择要处理的事件case FD_ACCEPT:{ //接收请求事件 sockConn=accept(sockSer,(SOCKADDR*) &addrCli,&len); WSAAsyncSelect(sockConn, hDlg,WM_SOCKET,FD_READ | FD_CLOSE); }break;case FD_READ: { //可读事件 recv(sockConn,recvbuf,256,0); //接收消息strcat_s(clibuf,recvbuf);//将接收到的消息添加到列表框中SendDlgItemMessage(hDlg,IDC_RECVBUF,LB_ADDSTRING,0,(LPARAM)clibuf);strcpy_s(clibuf, "客户端: >"); } //重新给字符串赋值 break; case FD_CLOSE: { //关闭连接事件 MessageBoxA(NULL, "正常关闭连接", "tip", 0); } break; }//switch (WSAGETSELECTEVENT(lParam)) }//elsebreak;case WM_COMMAND:switch(LOWORD(wParam) ){ case IDC_QUIT: //单击了退出按钮EndDialog(hDlg, LOWORD(wParam));closesocket(sockSer); //关闭套接字 WSACleanup(); //卸载WinSock协议栈return TRUE; case IDC_CREATE: //单击了创建服务器按钮GetDlgItemText(hDlg,IDC_IP,ip,16); //获取编辑框中的IP值GetDlgItemText(hDlg,IDC_PORT,port,5);EnableWindow(GetDlgItem(hDlg,IDC_CREATE),FALSE); //禁用按钮sockSer=socket(AF_INET,SOCK_STREAM,0);//②设置异步方式WSAAsyncSelect(sockSer, hDlg,WM_SOCKET,FD_ACCEPT); addrSer.sin_family=AF_INET;addrSer.sin_port=htons(atoi(port));addrSer.sin_addr.S_un.S_addr=inet_addr(ip);bind(sockSer,(SOCKADDR*) &addrSer,len); //绑定套接字listen(sockSer,5); //监听 break;case IDC_SEND: //单击了发送按钮GetDlgItemText(hDlg,IDC_SENDBUF,sendbuf,256);send(sockConn,sendbuf,strlen(sendbuf)+1,0); //发送消息SetDlgItemText(hDlg,IDC_SENDBUF,NULL); //清空编辑框strcat_s(serbuf,sendbuf);//将已发送的消息添加到列表框中SendDlgItemMessage(hDlg,IDC_RECVBUF,LB_ADDSTRING,0,(LPARAM)serbuf);strcpy_s(serbuf, "服务器: >");break; } //switch(LOWORD(wParam) ) }//switch (message) return (INT_PTR)FALSE;
}
客户端(窗口)
#include "stdafx.h"
#include "Exp07_AsyncClient.h"#include<WINSOCK2.h>
#pragma comment(lib,"ws2_32.lib")#define WM_SOCKET WM_USER+0x10 //①自定义socket消息#define MAX_LOADSTRING 100// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名SOCKET sockCli; //声明客户端套接字
SOCKADDR_IN addrSer;// 此代码模块中包含的函数的前向声明:
BOOL InitInstance(HINSTANCE, int);
INT_PTR CALLBACK AsyncClientProc(HWND, UINT, WPARAM, LPARAM);int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPTSTR lpCmdLine,_In_ int nCmdShow)
{UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);// TODO: 在此放置代码。MSG msg;HACCEL hAccelTable;// 初始化全局字符串LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadString(hInstance, IDC_EXP07_ASYNCCLIENT, szWindowClass, MAX_LOADSTRING); // 执行应用程序初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_EXP07_ASYNCCLIENT));// 主消息循环:while (GetMessage(&msg, NULL, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}return (int) msg.wParam;
}//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{HWND hWnd;hInst = hInstance; // 将实例句柄存储在全局变量中hWnd =CreateDialog(hInstance, MAKEINTRESOURCE(IDD_ASYNCCLIENT), GetDesktopWindow(), AsyncClientProc);if (!hWnd){return FALSE;}ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return TRUE;
}// “关于”框的消息处理程序。
INT_PTR CALLBACK AsyncClientProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{UNREFERENCED_PARAMETER(lParam);char ip[16], port[5];char sendbuf[256],recvbuf[256],ren[10]; char serbuf[256]="服务器: >", clibuf[256]="客户端: >";int len =sizeof(SOCKADDR);int res;switch (message){case WM_INITDIALOG: //对话框初始化SetDlgItemText(hDlg,IDC_IP,"127.0.0.1");SetDlgItemText(hDlg,IDC_PORT,"5566");WSADATA wsaData;WSAStartup(MAKEWORD(2,2), &wsaData); //加载协议栈sockCli=socket(AF_INET,SOCK_STREAM,0); //创建套接字//设置异步方式WSAAsyncSelect(sockCli, hDlg,WM_SOCKET, FD_READ |FD_CLOSE); break;case WM_SOCKET: //自定义消息 switch (WSAGETSELECTEVENT(lParam)){case FD_READ: { //可读事件 recv(sockCli,recvbuf,256,0); //接收信息strcat_s(serbuf,recvbuf);//将接收到的数据添加到列表框中SendDlgItemMessage(hDlg,IDC_RECVBUF,LB_ADDSTRING,0,(LPARAM)serbuf);strcpy_s(serbuf, "服务器: >"); } //重新给字符串赋值 break; case FD_CLOSE: { //关闭连接事件 MessageBoxA(NULL, "正常关闭连接", "tip", 0); }break; } break; case WM_COMMAND:{ switch(LOWORD(wParam)) { case IDC_QUIT: //单击了退出按钮EndDialog(hDlg, LOWORD(wParam));closesocket(sockCli);WSACleanup();break; case IDC_CONN: //单击了“连接服务器”按钮GetDlgItemText(hDlg,IDC_IP,ip,16); //获取ipGetDlgItemText(hDlg,IDC_PORT,port,5);EnableWindow(GetDlgItem(hDlg,IDC_CONN),FALSE); //禁用连接按钮addrSer.sin_family=AF_INET;addrSer.sin_port=htons(atoi(port));addrSer.sin_addr.S_un.S_addr=inet_addr(ip); res =connect(sockCli,(SOCKADDR*)&addrSer,sizeof(SOCKADDR));// itoa(res,ren,10);// MessageBox(NULL,ren,"通知",0); if(res ==10035 || res==-1)MessageBox(NULL,"客户端连接服务器成功","通知",0); else MessageBox(NULL,"客户端连接服务器失败","警告",0); break;case IDC_SEND: //单击了“发送”按钮GetDlgItemText(hDlg,IDC_SENDBUF,sendbuf,256); //获得发送框的内容send(sockCli,sendbuf,strlen(sendbuf)+1,0); //发送消息SetDlgItemText(hDlg,IDC_SENDBUF,""); //清空发送框strcat_s(clibuf,sendbuf); SendDlgItemMessage(hDlg,IDC_RECVBUF,LB_ADDSTRING,0,(LPARAM)clibuf);strcpy_s(clibuf, "客户端: >"); //重新给字符串赋值 break;}//switch(LOWORD(wParam))}//case WM_COMMAND:}return (INT_PTR)FALSE;
}
服务器://
#include <afxwin.h>#include "stdafx.h"
#include <WINSOCK2.H>
#include <iostream>#pragma comment(lib,"WS2_32.lib")
#define BUF_SIZE 64 // 缓冲区大小sockaddr_in addrClient; // 客户端地址DWORD WINAPI AnswerThread(LPVOID lparam)
{ char buf[BUF_SIZE]; // 用于接受客户端数据的缓冲区 int retVal; // 调用各种Socket函数的返回值 SOCKET sClient=(SOCKET)(LPVOID)lparam; // 循环接收客户端的数据,直接客户端发送quit命令后退出。 while(true){ZeroMemory(buf,BUF_SIZE); // 清空接收数据的缓冲区retVal = recv(sClient,buf,BUFSIZ,0); // 接收来自客户端的数据,因为是非阻塞模式,所以即使没有数据也会继续if(SOCKET_ERROR == retVal) { int err = WSAGetLastError(); // 获取错误编码if(err == WSAEWOULDBLOCK) // 接收数据缓冲区暂无数据{Sleep(100);continue;}else if(err == WSAETIMEDOUT || err == WSAENETDOWN){printf("recv failed !\n"); closesocket(sClient); WSACleanup(); return -1; }} // 获取当前系统时间SYSTEMTIME st;GetLocalTime(&st);char sDateTime[30];sprintf(sDateTime, "%4d-%2d-%2d %2d:%2d:%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);// 打印输出的信息printf("%s, Recv From Client [%s:%d] :%s\n", sDateTime, inet_ntoa(addrClient.sin_addr), addrClient.sin_port, buf); // 如果客户端发送quit字符串,则服务器退出if(strcmp(buf, "quit") == 0){retVal = send(sClient,"quit",strlen("quit"),0); break;}else // 否则向客户端发送回显字符串{char msg[BUF_SIZE]; sprintf(msg, "Message received - %s", buf); while(true){// 向服务器发送数据retVal = send(sClient, msg, strlen(msg),0); if(SOCKET_ERROR == retVal) { int err = WSAGetLastError();if(err == WSAEWOULDBLOCK) // 无法立即完成非阻塞套接字上的操作{Sleep(500);continue;}else{printf("send failed !\n"); closesocket(sClient); WSACleanup(); return -1; }}break;} }}// 关闭套接字closesocket(sClient);
}int _tmain(int argc, _TCHAR* argv[])
{WSADATA wsd; // WSADATA变量,用于初始化Windows Socket SOCKET sServer; // 服务器套接字,用于监听客户端请求SOCKET sClient; // 客户端套接字,用于实现与客户端的通信 int retVal; // 调用各种Socket函数的返回值 // 初始化套接字动态库 if(WSAStartup(MAKEWORD(2,2),&wsd) != 0) { printf("WSAStartup failed !\n"); return 1; } // 创建用于监听的套接字 sServer = socket(AF_INET,SOCK_STREAM, IPPROTO_IP); if(INVALID_SOCKET == sServer) { printf("socket failed !\n"); WSACleanup(); return -1; } // 设置套接字为非阻塞模式int iMode = 1;retVal = ioctlsocket(sServer, FIONBIO, (u_long FAR*) &iMode);if(retVal == SOCKET_ERROR){printf("ioctlsocket failed !\n");WSACleanup();return -1;}// 设置服务器套接字地址 SOCKADDR_IN addrServ; addrServ.sin_family = AF_INET; addrServ.sin_port = htons(9990); // 监听端口为9990addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 绑定套接字sServer到本地地址,端口9990 retVal = bind(sServer,(const struct sockaddr*)&addrServ,sizeof(SOCKADDR_IN)); if(SOCKET_ERROR == retVal) { printf("bind failed !\n"); closesocket(sServer); WSACleanup(); return -1; } // 监听套接字 retVal = listen(sServer, SOMAXCONN); if(SOCKET_ERROR == retVal) { printf("listen failed !\n"); closesocket(sServer); WSACleanup(); return -1; } // 接受客户请求 printf("TCP Server start...\n");int addrClientlen = sizeof(addrClient); // 循环等待while(true){sClient = accept(sServer,(sockaddr FAR*)&addrClient,&addrClientlen); if(INVALID_SOCKET == sClient) { int err = WSAGetLastError();if(err == WSAEWOULDBLOCK) // 无法立即完成非阻塞套接字上的操作{Sleep(100);continue;}//else//{// //printf("accept failed !\n"); // //closesocket(sServer); // //WSACleanup(); // //return -1; // Sleep(100);// continue;//}} // 创建专用通信线程DWORD dwThreadId;CreateThread(NULL, NULL, AnswerThread, (LPVOID)sClient, 0, &dwThreadId);}// 释放套接字 closesocket(sServer); WSACleanup(); // 暂停,按任意键退出system("pause");return 0;
}客户端:
#include "stdafx.h"
#include <winsock2.h>
#include <string>
#include <iostream>#pragma comment(lib,"WS2_32.lib") #define BUF_SIZE 64 // 缓冲区大小 int _tmain(int argc, _TCHAR* argv[])
{WSADATA wsd; // 用于初始化Windows Socket SOCKET sHost; // 与服务器进行通信的套接字 SOCKADDR_IN servAddr; // 服务器地址 char buf[BUF_SIZE]; // 用于接受数据缓冲区 int retVal; // 调用各种Socket函数的返回值 // 初始化Windows Socketif(WSAStartup(MAKEWORD(2,2),&wsd) != 0) { printf("WSAStartup failed !\n"); return 1; } // 创建套接字 sHost = socket(AF_INET,SOCK_STREAM,IPPROTO_IP); if(INVALID_SOCKET == sHost) { printf("socket failed !\n"); WSACleanup(); return -1; }// 设置套接字为非阻塞模式int iMode = 1;retVal = ioctlsocket(sHost, FIONBIO, (u_long FAR*) &iMode);if(retVal == SOCKET_ERROR){printf("ioctlsocket failed !\n");WSACleanup();return -1;}// 设置服务器地址 servAddr.sin_family = AF_INET; servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 用户需要根据实际情况修改servAddr.sin_port = htons(9990); int sServerAddlen = sizeof(servAddr); // 计算地址的长度 // 循环等待while(true){// 连接服务器 Sleep( 200 );retVal = connect(sHost,(LPSOCKADDR)&servAddr,sizeof(servAddr)); Sleep( 200 );if(SOCKET_ERROR == retVal) { int err = WSAGetLastError();if(err == WSAEWOULDBLOCK || err == WSAEINVAL) // 无法立即完成非阻塞套接字上的操作{//Sleep(500);continue;}else if(err == WSAEISCONN) // 已建立连接{break;}else{//continue;printf("connect failed !\n"); closesocket(sHost); WSACleanup(); return -1; }} }// 循环向服务器发送字符串,并显示反馈信息。// 发送quit将使服务器程序退出,同时客户端程序自身也将退出while(true){// 向服务器发送数据 printf("Please input a string to send: "); std::string str;std::getline(std::cin, str); // 接收输入的数据ZeroMemory(buf,BUF_SIZE); strcpy(buf,str.c_str()); // 将用户输入的数据复制到buf中 while(true){// 向服务器发送数据retVal = send(sHost,buf,strlen(buf),0); if(SOCKET_ERROR == retVal) { int err = WSAGetLastError();if(err == WSAEWOULDBLOCK) // 无法立即完成非阻塞套接字上的操作{Sleep(500);continue;}else{printf("send failed !\n"); closesocket(sHost); WSACleanup(); return -1; }}break;} int count=0;while(true){ZeroMemory(buf,BUF_SIZE); // 清空接收数据的缓冲区retVal = recv(sHost,buf,sizeof(buf)+1,0); // 接收服务器回传的数据 if(SOCKET_ERROR == retVal) { int err = WSAGetLastError(); // 获取错误编码if(err == WSAEWOULDBLOCK) // 接收数据缓冲区暂无数据{Sleep(100);count=count+1;if (count<10){printf("waiting back msg !\n");continue;} else{printf("recv back msg failed! \n");break;}}else if(err == WSAETIMEDOUT || err == WSAENETDOWN){printf("recv failed !\n"); closesocket(sHost); WSACleanup(); return -1;}break;} break;} //ZeroMemory(buf,BUF_SIZE); // 清空接收数据的缓冲区//retVal = recv(sHost,buf,sizeof(buf)+1,0); // 接收服务器回传的数据 printf("Recv From Server: %s\n\n",buf); if(strcmp(buf, "quit") == 0) // 如果收到quit,则退出{printf("quit!\n");break;}}closesocket(sHost); WSACleanup(); system("pause");return 0;
}
高级Socket编程技术相关推荐
- TCP:利用Socket编程技术实现客户端向服务端上传一个图片。
问题: 利用Socket编程技术实现客户端向服务端上传一个图片的程序. 客户端: import java.io.*; import java.net.Socket;public class clien ...
- JAVA之Socket编程(技术总结)
1.socket编程实例1--Socket客户端(字符串)->请求到Socket服务端->响应客户端: 代码如下: import java.io.BufferedReader; impor ...
- Socket 编程实现基于 HTTP 协议的客户和服务
目录 前言 研究背景及意义 研究内容及方法 研究要求与目标 相关知识点 HTTP协议 TCP协议 UDP协议 Socket编程技术 需求分析 Socket编程 Swing包 多线程的应用 功能设计 功 ...
- Socket编程--自己动手的HTTP代理服务器
浏览器使用代理:Firefox浏览器: 选项->高级->连接->设置,选择手动配置代理. 实现http代理: 1.等待来自一个客户端的连接: 2.启动一个新线程来处理连接: Inpu ...
- JNI_编程技术__网文整理
Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 Chap 3:javah命令帮助信息... 16 Chap 4:用javah产生一个.h文件... 17 Chap5:j ...
- Unix网络编程(六)高级I/O技术之复用技术 select
转载:http://blog.csdn.net/michael_kong_nju/article/details/44887411 I/O复用技术 本文将讨论网络编程中的高级I/O复用技术,将从下面几 ...
- 鼠标绘图 c语言,c语言高级编程技术教程 图形显示方式与鼠标输入.doc
c语言高级编程技术教程 图形显示方式与鼠标输入 c语言高级编程技术教程 图形显示方式和鼠标输入 图形显示方式和鼠标输入 问题的提出编写程序,使用鼠标进行如下操作:按住鼠标器的任意键并移动,十字光 标将 ...
- 基于socket网络编程技术实现TCP和UDP的流程详解及实例
具体函数讲解太多,根据程序自行分析. 可以参考这篇文章: https://blog.csdn.net/qq_41687938/article/details/119102328?spm=1001.20 ...
- ole2高级编程技术 pdf_21天快速掌握Python语言,《21天学通Python》PDF版送给你去学...
Python的学习书籍小编看过很多,但是这本<21天学通Python>真的是堪称极品! 本书的作者团队成员为一线开发工程师.资深编程专家或专业培训师,在编程开发方面有着丰富的经验,并已出版 ...
最新文章
- 软件测试--利用组合覆盖法设计测试用例
- tf.Session().as_default的作用
- ES6 Fetch API和Cookie相关的知识点
- Winodws live writer
- 雅虎、领英接连退出中国,GitHub 会受到影响吗?
- 搭建Magento电子商务网站
- html动态资源加载进度,JavaScript_快速解决js动态改变dom元素属性后页面及时渲染的问题,今天实现一个进度条加载过程 - phpStudy...
- ajax 页面部分先显示图片后出数据
- SPOJ QTREE4 lct
- 文字和表单(checkbox/radio)元素垂直对齐方法,兼容Firefox和IE。
- 软件測试自学指南---从入门到精通
- 大学排行榜 : qs全球世界 大学排行榜
- Maya2018安装报错(错误代码1612)
- word之中快速插入已有公式的几种方法
- 电脑电源问题,导致攒机电脑无法开机
- java高德地图api开发平台_【高德地图API】从零开始学高德JS API(一)地图展现...
- 3D数学基础及坐标系统
- 片段中onCreate(),onCreateView()和onActivityCreated()的区别和用法
- 计算机连接网络被限制,wifi连接被限制怎么办,教您wifi显示网络受限如何解决
- 人的一生,到底在追求甚麼