C/C++ Socket - TCP 与 UDP 网络编程
前言
socket编程分为TCP和UDP两个模块,其中TCP是可靠的、安全的,常用于发送文件等,而UDP是不可靠的、不安全的,常用作视频通话等。
如下图:
头文件与库:
#include <WinSock2.h>#pragma comment(lib, "ws2_32.lib")
准备工作:
创建工程后,首先右键工程,选择属性
然后选择 C/C++ - 预处理器 - 预处理器定义
将字符串 _WINSOCK_DEPRECATED_NO_WARNINGS 添加到里面去,点击应用即可!
TCP
连接过程图:
创建tcp服务器和客户端都是按照上图的步骤来操作的!
1). 服务器
初始化套接字库
对应图中socket()WORD wVersion; WSADATA wsaData; int err;// 设置版本,可以理解为1.1 wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动 err = WSAStartup(wVersion, &wsaData);
创建tcp套接字
对应图中socket()// AF_INET:ipv4 AF_INET6:ipv6 SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
绑定到本机
对应图中bind()// 准备绑定信息 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 设置绑定网卡 addrSrv.sin_family = AF_INET; // 设置绑定网络模式 addrSrv.sin_port = htons(6000); // 设置绑定端口 // hton: host to network x86:小端 网络传输:htons大端// 绑定到本机 int retVal = bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
监听
对应图中listen()// 同时能接收10个链接,主要看参数二的设置个数 listen(sockSrv, 10);
接收连接请求,返回针对客户端的套接字
对应图中accept()SOCKET sockConn = accept(sockSrv, (SOCKADDR *)&addrCli, &len);
发送数据
对应图中write()sprintf_s(sendBuf, "hello client!\n"); int iSend = send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);
接收数据
对应图中read()recv(sockConn, recvBuf, 100, 0);
关闭套接字
对应图中close()closesocket(sockConn);
清理套接字库
WSACleanup();
具体实现代码:
#include <iostream>
#include <stdio.h>
#include <WinSock2.h>#pragma comment(lib, "ws2_32.lib")int main(void) {// 1.初始化套接字库WORD wVersion;WSADATA wsaData;int err;// 设置版本,可以理解为1.1wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动err = WSAStartup(wVersion, &wsaData);if (err != 0) {return err;}// 检查:网络低位不等于1 || 网络高位不等于1if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {// 清理套接字库WSACleanup();return -1;}// 2.创建tcp套接字 // AF_INET:ipv4 AF_INET6:ipv6SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);// 准备绑定信息SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 设置绑定网卡addrSrv.sin_family = AF_INET; // 设置绑定网络模式addrSrv.sin_port = htons(6000); // 设置绑定端口// hton: host to network x86:小端 网络传输:htons大端// 3.绑定到本机int retVal = bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));if (retVal == SOCKET_ERROR) {printf("Failed bind:%d\n", WSAGetLastError());return -1;}// 4.监听,同时能接收10个链接if (listen(sockSrv, 10) == SOCKET_ERROR) {printf("Listen failed:%d", WSAGetLastError());return -1;}std::cout << "Server start at port: 6000" << std::endl;SOCKADDR_IN addrCli;int len = sizeof(SOCKADDR);char recvBuf[100];char sendBuf[100];while (1) {// 5.接收连接请求,返回针对客户端的套接字SOCKET sockConn = accept(sockSrv, (SOCKADDR *)&addrCli, &len);if (sockConn == SOCKET_ERROR) {//printf("Accept failed:%d", WSAGetLastError());std::cout << "Accept failed: " << WSAGetLastError() << std::endl;break;}//printf("Accept client IP:[%s]\n", inet_ntoa(addrCli.sin_addr));std::cout << "Accept client IP: " << inet_ntoa(addrCli.sin_addr) << std::endl;// 6.发送数据sprintf_s(sendBuf, "hello client!\n");int iSend = send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);if (iSend == SOCKET_ERROR) {std::cout << "send failed!\n";break;}// 7.接收数据recv(sockConn, recvBuf, 100, 0);std::cout << recvBuf << std::endl;// 关闭套接字closesocket(sockConn);}// 8.关闭套接字closesocket(sockSrv);// 9.清理套接字库WSACleanup();return 0;
}
2). 客户端
初始化套接字库
对应图中socket()WORD wVersion; WSADATA wsaData; int err;// 可以理解为1.1 wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动 err = WSAStartup(wVersion, &wsaData);// 创建TCP套接字 SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);
连接服务器
对应图中connect()// 连接服务器 int err_log = connect(sockCli, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
发送数据到服务器
对应图中write()char sendBuf[] = "你好,服务器,我是客户端!"; send(sockCli, sendBuf, strlen(sendBuf) + 1, 0);
接收服务器的数据
对应图中read()char recvBuf[100]; recv(sockCli, recvBuf, sizeof(recvBuf), 0);
关闭套接字并清除套接字库
对应图中close()closesocket(sockCli); WSACleanup();
具体实现代码:
#include <iostream>
#include <WinSock2.h>#pragma comment(lib, "ws2_32.lib")int main(void) {// 1.初始化套接字库WORD wVersion;WSADATA wsaData;int err;// 可以理解为1.1wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动err = WSAStartup(wVersion, &wsaData);if (err != 0) {return err;}// 检查:网络地位不等于1 || 网络高位不等于1if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {// 清理套接字库WSACleanup();return -1;}// 创建TCP套接字SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 服务器地址addrSrv.sin_port = htons(6000); // 端口号addrSrv.sin_family = AF_INET; // 地址类型(ipv4)// 2.连接服务器int err_log = connect(sockCli, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));if (err_log == 0) {printf("连接服务器成功!\n");} else {printf("连接服务器失败!\n");return -1;}char recvBuf[100];char sendBuf[] = "你好,服务器,我是客户端!";// 3.发送数据到服务器send(sockCli, sendBuf, strlen(sendBuf) + 1, 0);// 4.接收服务器的数据recv(sockCli, recvBuf, sizeof(recvBuf), 0);std::cout << recvBuf << std::endl;// 5.关闭套接字并清除套接字库closesocket(sockCli);WSACleanup();system("pause");return 0;
}
运行效果:
3). TCP聊天小项目
下面是根据上面的代码修改的一个聊天小项目(使用到了多线程)
只有一个服务器,服务器一直开启等待客户端连接;
客户都安可以开启多个,且可以一直连续的与服务器进行发送接收消息;
服务器给客户端发送数据,得通过1 - 9来区分到底给那个客户端发送消息,例如给第二个客户端发送消息:2你好,客户端
客户端那边接收到的数据是:你好,客户端
服务器代码:
#include <iostream>
#include <WinSock2.h>
#include <stdio.h>
#include <Windows.h>
#include <process.h>
#include <vector>
#include <conio.h>
#include <string.h>
#include <string>#pragma comment(lib, "ws2_32.lib")SOCKET sockSrv;
std::vector<SOCKET> vec_sockConn;
std::vector<SOCKADDR_IN> vec_sockaddr_in;
std::vector<int> vec_sockIndex;// 这个结构体用作线程参数
typedef struct SERVER_CLIENT {SOCKET server;SOCKADDR_IN client;int clientIndex;
}SC;// 判断有没有断开连接
bool IsSocketClosed(SOCKET clientSocket) {bool ret = false;HANDLE closeEvent = WSACreateEvent();WSAEventSelect(clientSocket, closeEvent, FD_CLOSE);DWORD dwRet = WaitForSingleObject(closeEvent, 0);if (dwRet == WSA_WAIT_EVENT_0)ret = true;else if (dwRet == WSA_WAIT_TIMEOUT)ret = false;WSACloseEvent(closeEvent);return ret;
}// 接收请求
unsigned int WINAPI ThreadAccept(LPVOID p) {static int i = 0;while (1) {SOCKADDR_IN addrCli;int len = sizeof(SOCKADDR);// 5.接收连接请求,返回针对客户端的套接字SOCKET sockConn = accept(sockSrv, (SOCKADDR *)&addrCli, &len);if (sockConn == SOCKET_ERROR) {printf("Accept failed:%d", WSAGetLastError());}// 存储当前服务器与客户端 连接绑定的socketvec_sockIndex.emplace_back(i++);vec_sockaddr_in.emplace_back(addrCli);vec_sockConn.emplace_back(sockConn);printf("\033[0;%d;40m客户端[%d]上线\033[0m\n", 31, i);}return 0;
}unsigned int WINAPI _ThreadRecv(LPVOID p) {char recvBuf[100];memset(recvBuf, 0, 100);SC _sc = *(SC *)p;while (1) {Sleep(20);if (IsSocketClosed(_sc.server) == true) {printf("客户端 [%d] 断开连接!\n", _sc.clientIndex + 1);break;}// 接收数据recv(_sc.server, recvBuf, 100, 0);if (strlen(recvBuf) == 0) {continue;}printf("接收到客户端 [%d] 的消息:%s\n", _sc.clientIndex + 1, recvBuf);memset(recvBuf, 0, 100);}return 0;
}unsigned int WINAPI ThreadRecv(LPVOID p) {static int index = 0;while (1) {// 还没有客户端与服务器进行连接if (vec_sockConn.size() == 0) {continue;}// 接收线程已经开启和客户端个数相等if (vec_sockConn.size() == index) {continue;}SC sc;sc.server = vec_sockConn.at(index);sc.client = vec_sockaddr_in.at(index);sc.clientIndex = vec_sockIndex.at(index);HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, _ThreadRecv, (void *)&sc, 0, NULL);index++;Sleep(20);}return 0;
}int main(void) {// 1.初始化套接字库WORD wVersion;WSADATA wsaData;int err;// 设置版本,可以理解为1.1wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动err = WSAStartup(wVersion, &wsaData);if (err != 0) {return err;}// 检查:网络低位不等于1 || 网络高位不等于1if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {// 清理套接字库WSACleanup();return -1;}// 2.创建tcp套接字 // AF_INET:ipv4 AF_INET6:ipv6sockSrv = socket(AF_INET, SOCK_STREAM, 0);// 准备绑定信息SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 设置绑定网卡addrSrv.sin_family = AF_INET; // 设置绑定网络模式addrSrv.sin_port = htons(6000); // 设置绑定端口// hton: host to network x86:小端 网络传输:htons大端// 3.绑定到本机int retVal = bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));if (retVal == SOCKET_ERROR) {printf("Failed bind:%d\n", WSAGetLastError());return -1;}// 4.监听,同时接收10个链接if (listen(sockSrv, 10) == SOCKET_ERROR) {printf("Listen failed:%d", WSAGetLastError());return -1;}std::cout << "Server start at port: 6000" << std::endl;// 线程句柄 // 创建线程HANDLE hThread_1 = (HANDLE)_beginthreadex(NULL, 0, ThreadAccept, NULL, 0, NULL);HANDLE hThread_2 = (HANDLE)_beginthreadex(NULL, 0, ThreadRecv, NULL, 0, NULL);//uiInit();//editPrint(0, ">");char sendBuf[100];while (1) {//printf("请输入发送内容:");char c = getchar(); // 输入发送给谁scanf_s("%s", sendBuf, 100); // 输入发送的内容if (strlen(sendBuf) == 0) {printf("输入内容为空或者超长!\n");}// 1 至 9if (c < '1' || c > '9' || vec_sockConn.size() == 0 || c - '0' >= vec_sockConn.size() + 1) {while ((c = getchar()) != '\n'); // 清空输入缓冲区memset(sendBuf, 0, 100);printf("输入内容不符合规则!\n");continue;}// 发送数据int index = --c - '0'; // 因为下标是从零开始的,所以c要先自减int iSend = send(vec_sockConn.at(index) , sendBuf, strlen(sendBuf) + 1, 0);if (iSend == SOCKET_ERROR) {std::cout << "send failed!\n";break;}memset(sendBuf, 0, 100);while ((c = getchar()) != '\n'); // 清空输入缓冲区}// 关闭套接字std::vector<SOCKET>::iterator it = vec_sockConn.begin();for (; it != vec_sockConn.end(); it++) {closesocket((SOCKET)(*it));}WaitForSingleObject(hThread_1, INFINITE);WaitForSingleObject(hThread_2, INFINITE);CloseHandle(hThread_1);CloseHandle(hThread_2);// 7.关闭套接字closesocket(sockSrv);// 8.清理套接字库WSACleanup();return 0;
}
客户端:
#include <iostream>
#include <WinSock2.h>
#include <process.h>
#include <stdio.h>#pragma comment(lib, "ws2_32.lib")SOCKET sockCli;// 判断有没有断开连接
bool IsSocketClosed(SOCKET clientSocket) {bool ret = false;HANDLE closeEvent = WSACreateEvent();WSAEventSelect(clientSocket, closeEvent, FD_CLOSE);DWORD dwRet = WaitForSingleObject(closeEvent, 0);if (dwRet == WSA_WAIT_EVENT_0)ret = true;else if (dwRet == WSA_WAIT_TIMEOUT)ret = false;WSACloseEvent(closeEvent);return ret;
}unsigned int WINAPI ThreadRecv(LPVOID p) {char recvBuf[100];memset(recvBuf, 0, 100);while (1) {Sleep(20);if (IsSocketClosed(sockCli) == true) {printf("服务器 断开连接!\n");break;}// 接收服务器的数据recv(sockCli, recvBuf, sizeof(recvBuf), 0);if (strlen(recvBuf) == 0) continue;std::cout << recvBuf << std::endl;memset(recvBuf, 0, 100);}return 0;
}int main(void) {// 1.初始化套接字库WORD wVersion;WSADATA wsaData;int err;// 可以理解为1.1wVersion = MAKEWORD(1, 1); // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动err = WSAStartup(wVersion, &wsaData);if (err != 0) {return err;}// 检查:网络地位不等于1 || 网络高位不等于1if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {// 清理套接字库WSACleanup();return -1;}// 创建TCP套接字sockCli = socket(AF_INET, SOCK_STREAM, 0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 服务器地址addrSrv.sin_port = htons(6000); // 端口号addrSrv.sin_family = AF_INET; // 地址类型(ipv4)// 连接服务器int err_log = connect(sockCli, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));if (err_log == 0) {printf("连接服务器成功!\n");} else {printf("连接服务器失败!\n");return -1;}// 线程句柄 // 创建线程HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadRecv, NULL, 0, NULL);char sendBuf[100];while (1) {//printf("请输入发送内容:");scanf_s("%s", sendBuf, 100);// 发送数据到服务器send(sockCli, sendBuf, strlen(sendBuf) + 1, 0);memset(sendBuf, 0, 100);char c;while ((c = getchar()) != '\n');}WaitForSingleObject(hThread, INFINITE);CloseHandle(hThread);// 关闭套接字并清除套接字库closesocket(sockCli);WSACleanup();system("pause");return 0;
}
运行效果:
UDP
UDP就比较简单了,步骤比tcp要少一些。
连接过程图:
1). 服务器
初始化套接字库
WORD wVersion; WSADATA wsaData; int err;wVersion = MAKEWORD(1, 1);
创建套接字
SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);
绑定
// SOCKADDR_IN addrSrv; 省略了定义和赋值 bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
接收数据
char recvBuf[100]; recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len);
发送数据
char sendBuf[] = "hello Client,I'm Server!\n"; sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrCli, len);
关闭
closesocket(sockSrv); WSACleanup();
具体实现代码:
#include <WinSock2.h>
#include <iostream>#pragma comment(lib, "ws2_32.lib")int main(void) {// 初始化套接字库WORD wVersion;WSADATA wsaData;int err;wVersion = MAKEWORD(1, 1);err = WSAStartup(wVersion, &wsaData);if (err != 0) {return err;}if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {WSACleanup();return -1;}// 创建套接字SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(6001);// 绑定到本机6001端口bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));// 接收请求,处理请求SOCKADDR_IN addrCli;int len = sizeof(SOCKADDR);char sendBuf[] = "hello Client,I'm Server!\n";char recvBuf[100];std::cout << "start UDP server with port 6001" << std::endl;while (1) {// 接收数据recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len);std::cout << "Recv:" << recvBuf << std::endl;// 发送数据sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrCli, len);std::cout << "Send:" << sendBuf << std::endl;}closesocket(sockSrv);WSACleanup();return 0;
}
2). 客户端
初始化套接字库
WORD wVersion; WSADATA wsaData; int err;wVersion = MAKEWORD(1, 1);
创建UDP套接字
SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0); SOCKADDR_IN addrSrv;
接收数据
char recvBuf[100]; recvfrom(sockCli, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len);
发送数据
char sendBuf[] = "hello Client,I'm Server!\n"; sendto(sockCli, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrSrv, len);
关闭
closesocket(sockSrv); WSACleanup();
具体实现代码:
#include <WinSock2.h>
#include <iostream>#pragma comment(lib, "ws2_32.lib")int main(void) {// 初始化套接字库WORD wVersion;WSADATA wsaData;int err;wVersion = MAKEWORD(1, 1);err = WSAStartup(wVersion, &wsaData);if (err != 0) {return err;}if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {WSACleanup();return -1;}// 创建UDP套接字SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(6001);SOCKADDR_IN addrCli;int len = sizeof(SOCKADDR);char sendBuf[] = "hello, I'm Client!\n";char recvBuf[100];std::cout << "send to Server: " << sendBuf << std::endl;sendto(sockCli, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrSrv, len);recvfrom(sockCli, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len);std::cout << "recv from: " << recvBuf << std::endl;closesocket(sockCli);WSACleanup();system("pause");return 0;
}
运行效果:
总结
socket的具体细节用法我不太清楚,现阶段也只是熟悉TCP的一些简单操作,UDP的话也还不是太懂,不懂的是不知道在具体项目中该如何进行使用它们。
那个TCP的小项目也只是自己琢磨搞出来的,不知掉具体项目会不会这样去写!
C/C++ Socket - TCP 与 UDP 网络编程相关推荐
- python socket tcp客户端_python网络编程socketserver模块(实现TCP客户端/服务器)
摘录python核心编程 socketserver(python3.x版本重新命名)是标准库中的网络编程的高级模块.通过将创建网络客户端和服务器所必须的代码封装起来,简化了模板,为你提供了各种各样的类 ...
- TCP、UDP网络编程面试题
TCP.UDP.Socket.HTTP网络编程面试题 什么是网络编程 网络编程的本质是多台计算机之间的数据交换.数据传递本身没有多大的难度,不就是把一个设备中的数据发送给其他设备,然后接受另外一个设备 ...
- TCP与UDP网络编程总结(一)
(1):TCP网络编程 我们注意到服务端与客户端通信时是通过客户端的套接字相互通信的,那么服务端的套接字主要是干什么用的呢? TCP服务端设置监听套接字时 int listen(int sock,in ...
- JAVA UDP网络编程学习笔记
一.UDP网络编程概述 采用TCP协议通信时,客户端的Socket必须先与服务器建立连接,连接建立成功后,服务器端也会持有客户端连接的Socket,客户端的Socket与服务器端的Socket是对应的 ...
- <UDP网络编程>——《计算机网络》
目录 1. 网络基础知识 1.1 理解源IP地址和目的IP地址 1.2 认识端口号 1.3 理解 "端口号" 和 "进程ID" 1.3.1 理解源端口号和目的端 ...
- 【Java】UDP网络编程
文章目录 前言 DatagramSocket DatagramPacket 注意事项与区别 代码演示 前言 UDP(user datagram protocol)的中文叫用户数据报协议,属于传输层. ...
- python交互式编程客户端_【python】UDP网络编程:实现服务端与客户端的交互、简单的AI智能模式...
关于UDP网络编程 UDP(user datagram protocol)的中文叫用户数据报协议,属于传输层.UDP是面向非连接的协议,它不与对方建立连接,而是直接把要发的数据发给对方. [UDP网络 ...
- C语言笔记-26-网络-UDP网络编程
C语言笔记-26-网络-UDP网络编程 文章目录 C语言笔记-26-网络-UDP网络编程 前言 一.UDP编程模型概括 三.UDP编程模型代码 UDP服务端 UDP客户端 总结 前言 自学笔记,没有历 ...
- python socket 主动断开_Python网络编程tcp详解(基础篇十四)
网络编程tcp 1 TCP详解 <1> tcp概述 TCP:英文全拼(Transmission Control Protocol)简称传输控制协议,它是一种面向连接的.可靠的.基于字节流的 ...
最新文章
- 一款优秀的JavaScript框架—AngularJS
- jquery实现点击浏览器后退,上一页面自动刷新
- LeetCode Course Schedule II(拓扑排序)
- 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1071:菲波那契数
- XML Schema全接触 (这里主要介绍W3C的Schema标准语法)
- POJ 2240 ZOJ 1082 Arbitrage 最短路,c++ stl pass g++ tle 难度:0
- Apache-DBUtils实现CRUD操作,已封装的API实现jdbc对数据库进行操作
- idea将本地项目推送至远程仓库(图形化版本01)
- 彻底搞懂阻塞、非阻塞、同步、异步
- HTML打开网页拒绝访问,WindowsApps无法访问怎么解决?
- Mysql权限控制 - 允许用户远程连接
- adobe reader运行时出现“Invalid plugin detected”错误的解决办法
- 数据结构设计_数据结构设计之实现 Trie (前缀树)[Sumatran Rhinoceros]
- Python开源BI工具Superset的搭建与使用
- 打印机扫描显示服务器没有响应,打印机扫描一体机能够打印却不能扫描,提示缺少WIA的驱动程序...
- android属性动画郭霖,GitHub - zhuanghongji/mp-android-index: 微信公众号「郭霖」「鸿洋」「玉刚说」「谷歌开发者」历史文章索引...
- 写过的比较难受的题目
- 那门用Python讲授的程序设计课程能带给学生什么
- 【MikTe安装】最新的MiKTeX替换CTEX默认安装的MiKTeX
- 怎么将EXCEL转换为财务软件导入需要的XML格式,干货到,EXCEL如何转换为财务软件导入数据所需格式
热门文章
- 胡玮炜辞职摩拜,意味着摩拜正式进入美团时代
- python制作冰花_一种冰花效果的UV涂料及其制备方法
- android 多个图层,Android图层列表layer-list
- 关联规则可视化python语言_关联规则可视化 - 猪猪daxia的个人空间 - OSCHINA - 中文开源技术交流社区...
- 极客头条 | 5月18日科技要闻:华为库存至少够缓冲一年;张朝阳质疑 5G 微波危害;苹果iOS 13不受支持机型曝光
- springboot读取yml数组
- 这次河北地震, Blog 传播速度
- 对某加固新闻应用的hook
- php 调用include 方法,php include的使用法详解
- Essentials