dev 准备v1.0.4,发现tthread.h重复包含bug
This commit is contained in:
parent
4d3591d707
commit
5e506c69d2
@ -2,11 +2,12 @@
|
|||||||
#define _SSOCKET_H_
|
#define _SSOCKET_H_
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define SSOCKET_VERSION_MAJOR 1
|
// #define SSOCKET_VERSION_MAJOR 1
|
||||||
#define SSOCKET_VERSION_MINOR 0
|
// #define SSOCKET_VERSION_MINOR 0
|
||||||
#define SSOCKET_VERSION_PATCH 2
|
// #define SSOCKET_VERSION_PATCH
|
||||||
#include "sysenv.h"
|
#include "sysenv.h"
|
||||||
|
|
||||||
#if _OS_WIN
|
#if _OS_WIN
|
||||||
@ -18,9 +19,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if WIN_PART
|
#if WIN_PART
|
||||||
#include <winsock2.h>
|
#include <Winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <Ws2tcpip.h>
|
||||||
#include <windows.h>
|
#include <CoreWindow.h>
|
||||||
#define strcasecmp _stricmp
|
#define strcasecmp _stricmp
|
||||||
#define strncasecmp _strnicmp
|
#define strncasecmp _strnicmp
|
||||||
#define socklen_t int
|
#define socklen_t int
|
||||||
@ -29,14 +30,11 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#define SOCKET long long int
|
#define SOCKET long long int
|
||||||
#define INVALID_SOCKET (SOCKET)(~0)
|
#define INVALID_SOCKET (SOCKET)(~0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "tthread.h"
|
|
||||||
|
|
||||||
#ifndef ZZY_SLEEP
|
#ifndef ZZY_SLEEP
|
||||||
#define ZZY_SLEEP
|
#define ZZY_SLEEP
|
||||||
#if WIN_PART
|
#if WIN_PART
|
||||||
@ -87,7 +85,6 @@ static inline int make_client_sock(SOCKET* sock, const char* connect_ip, unsigne
|
|||||||
static inline void close_sock(SOCKET sock);
|
static inline void close_sock(SOCKET sock);
|
||||||
static inline void out_sock_err(FILE* output, int errcode);
|
static inline void out_sock_err(FILE* output, int errcode);
|
||||||
static inline void get_sock_err(char* buff_128, size_t buff_len, int errcode);
|
static inline void get_sock_err(char* buff_128, size_t buff_len, int errcode);
|
||||||
static inline void sock_thread(void(*thread_func)(void*), void* data);
|
|
||||||
|
|
||||||
#define _SOCKET_TEST_IP "127.0.0.1"
|
#define _SOCKET_TEST_IP "127.0.0.1"
|
||||||
#define _SOCKET_TEST_PORT 6789
|
#define _SOCKET_TEST_PORT 6789
|
||||||
@ -101,23 +98,24 @@ static inline int make_sock_tcp4(SOCKET* sock) { return _sock(sock, AF_INET, SOC
|
|||||||
static inline int make_sock_tcp6(SOCKET* sock) { return _sock(sock, AF_INET6, SOCK_STREAM); }
|
static inline int make_sock_tcp6(SOCKET* sock) { return _sock(sock, AF_INET6, SOCK_STREAM); }
|
||||||
static inline int make_sock_udp4(SOCKET* sock) { return _sock(sock, AF_INET, SOCK_DGRAM); }
|
static inline int make_sock_udp4(SOCKET* sock) { return _sock(sock, AF_INET, SOCK_DGRAM); }
|
||||||
static inline int make_sock_udp6(SOCKET* sock) { return _sock(sock, AF_INET6, SOCK_DGRAM); }
|
static inline int make_sock_udp6(SOCKET* sock) { return _sock(sock, AF_INET6, SOCK_DGRAM); }
|
||||||
|
//不推荐
|
||||||
static inline int make_sock(SOCKET* sock) { return make_sock_tcp4(sock); };
|
static inline int make_sock(SOCKET* sock) { return make_sock_tcp4(sock); };
|
||||||
|
|
||||||
static inline int _sock(SOCKET* sock, int af, int type) {
|
static inline int _sock(SOCKET* sock, int af, int type) {
|
||||||
#ifdef WIN_PART
|
#ifdef WIN_PART
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||||
return ERR_SOCK_WSAStartup;
|
return -ERR_SOCK_WSAStartup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HIBYTE(wsaData.wVersion) != 2 || \
|
if (HIBYTE(wsaData.wVersion) != 2 || \
|
||||||
LOBYTE(wsaData.wVersion) != 2) {
|
LOBYTE(wsaData.wVersion) != 2) {
|
||||||
return ERR_SOCK_DETERMINE_AGREEMENT;
|
return -ERR_SOCK_DETERMINE_AGREEMENT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
*sock = socket(af, type, 0);
|
*sock = socket(af, type, 0);
|
||||||
if (*sock == INVALID_SOCKET) {
|
if (*sock == INVALID_SOCKET) {
|
||||||
return ERR_SOCK_CREATE_SOCKET;
|
return -ERR_SOCK_CREATE_SOCKET;
|
||||||
}
|
}
|
||||||
return ERR_SOCK_SUCCESS;
|
return ERR_SOCK_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -141,19 +139,19 @@ static inline int _socket(SOCKET* sock, const char* ip, const char* port) {
|
|||||||
struct addrinfo* res_addr = NULL;
|
struct addrinfo* res_addr = NULL;
|
||||||
int res = getaddrinfo(ip, port, &inf, &res_addr);
|
int res = getaddrinfo(ip, port, &inf, &res_addr);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
return _sock_eai_res_map(res);
|
return -(_sock_eai_res_map(res));
|
||||||
}
|
}
|
||||||
for (struct addrinfo* p = res_addr; p != NULL; p = p->ai_next) {
|
for (struct addrinfo* p = res_addr; p != NULL; p = p->ai_next) {
|
||||||
if (*sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) {
|
if (*sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) {
|
||||||
if (*sock == INVALID_SOCKET) {
|
if (*sock == INVALID_SOCKET) {
|
||||||
return ERR_SOCK_CREATE_SOCKET;
|
return -ERR_SOCK_CREATE_SOCKET;
|
||||||
}
|
}
|
||||||
freeaddrinfo(res_addr);
|
freeaddrinfo(res_addr);
|
||||||
return ERR_SOCK_SUCCESS;
|
return -ERR_SOCK_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeaddrinfo(res_addr);
|
freeaddrinfo(res_addr);
|
||||||
return ERR_SOCK_CONNECT;
|
return -ERR_SOCK_CONNECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int _connect(SOCKET sock, const char* ip, const char* port) {
|
static inline int _connect(SOCKET sock, const char* ip, const char* port) {
|
||||||
@ -170,7 +168,7 @@ static inline int _connect(SOCKET sock, const char* ip, const char* port) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeaddrinfo(res_addr);
|
freeaddrinfo(res_addr);
|
||||||
return ERR_SOCK_CONNECT;
|
return -ERR_SOCK_CONNECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int _bind(SOCKET sock, const char* ip, const char* port) {
|
static inline int _bind(SOCKET sock, const char* ip, const char* port) {
|
||||||
@ -178,7 +176,7 @@ static inline int _bind(SOCKET sock, const char* ip, const char* port) {
|
|||||||
struct addrinfo* res_addr = NULL;
|
struct addrinfo* res_addr = NULL;
|
||||||
int res = getaddrinfo(ip, port, &inf, &res_addr);
|
int res = getaddrinfo(ip, port, &inf, &res_addr);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
return ERR_SOCK_ADDRINFO;
|
return -ERR_SOCK_ADDRINFO;
|
||||||
}
|
}
|
||||||
for (struct addrinfo* p = res_addr; p != NULL; p = p->ai_next) {
|
for (struct addrinfo* p = res_addr; p != NULL; p = p->ai_next) {
|
||||||
if (bind(sock, p->ai_addr, p->ai_addrlen) == 0) {
|
if (bind(sock, p->ai_addr, p->ai_addrlen) == 0) {
|
||||||
@ -187,7 +185,7 @@ static inline int _bind(SOCKET sock, const char* ip, const char* port) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeaddrinfo(res_addr);
|
freeaddrinfo(res_addr);
|
||||||
return ERR_SOCK_CONNECT;
|
return -ERR_SOCK_CONNECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int _bindlisten(SOCKET sock, const char* ip, const char* port) {
|
static inline int _bindlisten(SOCKET sock, const char* ip, const char* port) {
|
||||||
@ -196,7 +194,7 @@ static inline int _bindlisten(SOCKET sock, const char* ip, const char* port) {
|
|||||||
if (listen(sock, SOMAXCONN) == 0) {
|
if (listen(sock, SOMAXCONN) == 0) {
|
||||||
return ERR_SOCK_SUCCESS;
|
return ERR_SOCK_SUCCESS;
|
||||||
}
|
}
|
||||||
return ERR_SOCK_LISTEN;
|
return -ERR_SOCK_LISTEN;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -218,16 +216,16 @@ static inline int sock_accpet(SOCKET sock,SOCKET* client, char** accept_ip, unsi
|
|||||||
socklen_t addrLen = sizeof(struct sockaddr_in);
|
socklen_t addrLen = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
if(client == NULL) {
|
if(client == NULL) {
|
||||||
return ERR_SOCK_NULLPTR;
|
return -ERR_SOCK_NULLPTR;
|
||||||
}
|
}
|
||||||
*client = accept(sock,(struct sockaddr*) &caddr, &addrLen);
|
*client = accept(sock,(struct sockaddr*) &caddr, &addrLen);
|
||||||
if (*client == -1) {
|
if (*client == -1) {
|
||||||
return ERR_SOCK_ACCEPT;
|
return -ERR_SOCK_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ip = (char*)malloc(32);
|
char* ip = (char*)malloc(32);
|
||||||
if(ip == NULL) {
|
if(ip == NULL) {
|
||||||
return ERR_SOCK_MALLOC;
|
return -ERR_SOCK_MALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
int buffLen = strlen( inet_ntoa(caddr.sin_addr) );
|
int buffLen = strlen( inet_ntoa(caddr.sin_addr) );
|
||||||
@ -244,7 +242,10 @@ static inline int sock_accpet(SOCKET sock,SOCKET* client, char** accept_ip, unsi
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline int make_server_sock(SOCKET* sock, const char* server_ip, unsigned short port) {
|
static inline int make_server_sock(SOCKET* sock, const char* server_ip, unsigned short port) {
|
||||||
int res = make_sock(sock);
|
char buf[8] = { 0 };
|
||||||
|
sprintf(buf, "%u", port);
|
||||||
|
|
||||||
|
int res = _socket(sock, server_ip, buf);
|
||||||
if(res != ERR_SOCK_SUCCESS) {
|
if(res != ERR_SOCK_SUCCESS) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -258,7 +259,10 @@ static inline int make_server_sock(SOCKET* sock, const char* server_ip, unsigned
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline int make_client_sock(SOCKET* sock, const char* connect_ip, unsigned short port) {
|
static inline int make_client_sock(SOCKET* sock, const char* connect_ip, unsigned short port) {
|
||||||
int res = make_sock(sock);
|
char buf[8] = { 0 };
|
||||||
|
sprintf(buf, "%u", port);
|
||||||
|
|
||||||
|
int res = _socket(sock, connect_ip, buf);
|
||||||
if(res != ERR_SOCK_SUCCESS) {
|
if(res != ERR_SOCK_SUCCESS) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -274,9 +278,7 @@ static inline int make_client_sock(SOCKET* sock, const char* connect_ip, unsigne
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void close_sock(SOCKET sock) {
|
static inline void close_sock(SOCKET sock) {
|
||||||
if(sock == -1) {
|
if(sock == -1) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if WIN_PART
|
#if WIN_PART
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
#elif LINUX_PART
|
#elif LINUX_PART
|
||||||
@ -296,14 +298,26 @@ static inline void get_sock_err(char* buff_128, size_t buff_len, int errcode) {
|
|||||||
// ERR_SOCK_SUCCESS,
|
// ERR_SOCK_SUCCESS,
|
||||||
// ERR_SOCK_MALLOC,
|
// ERR_SOCK_MALLOC,
|
||||||
// ERR_SOCK_NULLPTR,
|
// ERR_SOCK_NULLPTR,
|
||||||
|
|
||||||
// ERR_SOCK_WSAStartup,
|
// ERR_SOCK_WSAStartup,
|
||||||
// ERR_SOCK_DETERMINE_AGREEMENT,
|
// ERR_SOCK_DETERMINE_AGREEMENT,
|
||||||
// ERR_SOCK_CREATE_SOCKET,
|
// ERR_SOCK_CREATE_SOCKET,
|
||||||
// ERR_SOCK_BIND,
|
// ERR_SOCK_BIND,
|
||||||
// ERR_SOCK_LISTEN,
|
// ERR_SOCK_LISTEN,
|
||||||
// ERR_SOCK_ACCEPT,
|
// ERR_SOCK_ACCEPT,
|
||||||
|
|
||||||
// ERR_SOCK_CONNECT,
|
// ERR_SOCK_CONNECT,
|
||||||
|
|
||||||
|
// ERR_SOCK_ADDRINFO,
|
||||||
|
// //getaddrinfo
|
||||||
|
// ERR_SOCK_EAI_MAPPING_NOT_EXIST,
|
||||||
|
// ERR_SOCK_EAI_AGAIN,
|
||||||
|
// ERR_SOCK_EAI_BADFLAGS,
|
||||||
|
// ERR_SOCK_EAI_FAIL,
|
||||||
|
// ERR_SOCK_EAI_FAMILY,
|
||||||
|
// ERR_SOCK_EAI_MEMORY,
|
||||||
|
// ERR_SOCK_EAI_NONAME,
|
||||||
|
// ERR_SOCK_EAI_SERVICE,
|
||||||
|
// ERR_SOCK_EAI_SOCKTYPE,
|
||||||
// };
|
// };
|
||||||
// https://learn.microsoft.com/zh-cn/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo?redirectedfrom=MSDN
|
// https://learn.microsoft.com/zh-cn/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo?redirectedfrom=MSDN
|
||||||
// https://learn.microsoft.com/en-gb/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo?redirectedfrom=MSDN
|
// https://learn.microsoft.com/en-gb/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo?redirectedfrom=MSDN
|
||||||
@ -320,15 +334,6 @@ static inline void get_sock_err(char* buff_128, size_t buff_len, int errcode) {
|
|||||||
sprintf(buff_128, "%3d", errcode);
|
sprintf(buff_128, "%3d", errcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sock_thread(void(*thread_func)(void*), void* data) {
|
|
||||||
#if WIN_PART
|
|
||||||
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, data, 0, NULL);
|
|
||||||
#elif LINUX_PART
|
|
||||||
pthread_t pid;
|
|
||||||
pthread_create(&pid, 0, (void*(*)(void*))thread_func, data);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,15 +2,11 @@
|
|||||||
#define _TTHREAD_H_
|
#define _TTHREAD_H_
|
||||||
|
|
||||||
#include "sysenv.h"
|
#include "sysenv.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#if _OS_WIN
|
#if _OS_WIN
|
||||||
#include <CoreWindow.h>
|
#include <CoreWindow.h>
|
||||||
//#include <handleapi.h>
|
|
||||||
//#include <synchapi.h>
|
|
||||||
//#include <processthreadsapi.h>
|
|
||||||
|
|
||||||
typedef DWORD TID;
|
typedef DWORD TID;
|
||||||
typedef CRITICAL_SECTION MUTEX;
|
typedef CRITICAL_SECTION MUTEX;
|
||||||
typedef CONDITION_VARIABLE COND;
|
typedef CONDITION_VARIABLE COND;
|
||||||
@ -36,9 +32,9 @@ typedef pthread_cond_t COND;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
// #ifdef __cplusplus
|
||||||
extern "C" {
|
// extern "C" {
|
||||||
#endif
|
// #endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ERR_THREAD_SUCCESS,
|
ERR_THREAD_SUCCESS,
|
||||||
@ -131,7 +127,6 @@ static inline TID thread_self(void) {
|
|||||||
#elif _OS_LINUX
|
#elif _OS_LINUX
|
||||||
return pthread_self();
|
return pthread_self();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mutex part
|
// mutex part
|
||||||
@ -296,8 +291,8 @@ static inline int tvsnprintf(MUTEX* mutex, char* const buffer,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
// #ifdef __cplusplus
|
||||||
}
|
// }
|
||||||
#endif
|
// #endif
|
||||||
|
|
||||||
#endif // _TTHREAD_H_
|
#endif // _TTHREAD_H_
|
@ -2,6 +2,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <ssocket.h>
|
#include <ssocket.h>
|
||||||
|
// #include <tthread.h>
|
||||||
|
#include <tthread.h>
|
||||||
SOCKET cfd;
|
SOCKET cfd;
|
||||||
|
|
||||||
void receive_message(void* param)
|
void receive_message(void* param)
|
||||||
@ -37,7 +39,7 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
printf("conncet server success\n");
|
printf("conncet server success\n");
|
||||||
|
|
||||||
sock_thread(receive_message, NULL);
|
thread_create(NULL, receive_message, NULL);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
fgets(Buf, sizeof(Buf), stdin);
|
fgets(Buf, sizeof(Buf), stdin);
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#include <ssocket.h>
|
#include <ssocket.h>
|
||||||
|
#define _THREAD_H_
|
||||||
|
#include <tthread.h>
|
||||||
|
|
||||||
#define CLIENT_SIZE 32
|
#define CLIENT_SIZE 32
|
||||||
SOCKET sfd;
|
SOCKET sfd;
|
||||||
SOCKET cfds[CLIENT_SIZE];
|
SOCKET cfds[CLIENT_SIZE];
|
||||||
@ -69,7 +72,7 @@ void acceptfunc(void* param) {
|
|||||||
cfds[i] = sock;
|
cfds[i] = sock;
|
||||||
printf("<ip = %s, port = %u, socket = %lld>\n", ip, port, sock);
|
printf("<ip = %s, port = %u, socket = %lld>\n", ip, port, sock);
|
||||||
free(ip);
|
free(ip);
|
||||||
sock_thread(receive_message, (void*)psock);
|
thread_create(NULL, receive_message, (void*)psock);
|
||||||
goto CONTINUE;
|
goto CONTINUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,7 +94,7 @@ int main()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
printf("server start...\n");
|
printf("server start...\n");
|
||||||
sock_thread(acceptfunc, NULL);
|
thread_create(NULL, acceptfunc, NULL);
|
||||||
while(1) {
|
while(1) {
|
||||||
fgets(Buf, sizeof(Buf), stdin);
|
fgets(Buf, sizeof(Buf), stdin);
|
||||||
printf("%s", Buf);
|
printf("%s", Buf);
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
v1.0.1 ssocket
|
v1.0.1 dev
|
||||||
提供基础的windows与linux的跨平台tcp-ipv4协议
|
提供基础的windows与linux的跨平台tcp-ipv4协议
|
||||||
v1.0.2 ssocket
|
v1.0.2 dev
|
||||||
使用getaddrinfo重写部分内容,为未来兼容tcp/udp-ipv4/ipv6做准备
|
使用getaddrinfo重写部分内容,为未来兼容tcp/udp-ipv4/ipv6做准备
|
||||||
添加make_sock,make_sock_tcp4,make_sock_tcp6,make_sock_udp4,make_sock_udp6函数
|
添加make_sock,make_sock_tcp4,make_sock_tcp6,make_sock_udp4,make_sock_udp6函数
|
||||||
添加若干内置函数(以_func形式)
|
添加若干内置函数(以_func形式)
|
||||||
兼容老版本
|
兼容老版本
|
||||||
v1.0.3 ssocket
|
v1.0.3 dev
|
||||||
使用多头文件分离的方法将系统环境,线程,套接字分成三个文档
|
使用多头文件分离的方法将系统环境,线程,套接字分成三个文档
|
||||||
暂时兼容老版本,将在下个版本取消对前版本的兼容性
|
暂时兼容老版本,将在下个版本取消对前版本的兼容性
|
||||||
|
v1.0.4 alpha
|
||||||
|
通过了Windows和Linux的基础测试(不完全),
|
Loading…
x
Reference in New Issue
Block a user