#ifndef _SSOCKET_H_ #define _SSOCKET_H_ #include #include #define SSOCKET_VERSION_MAJOR 1 #define SSOCKET_VERSION_MINOR 0 #define SSOCKET_VERSION_PATCH 2 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) #define _OS_WIN 1 //define something for Windows (32-bit and 64-bit, this part is common) #ifdef _WIN64 #define _OS_WIN64 1 //define something for Windows (64-bit only) #else #define _OS_WIN32 1 //define something for Windows (32-bit only) #endif #elif __APPLE__ #define _OS_APPLE 1 #include #if TARGET_IPHONE_SIMULATOR #define _OS_APPLE_SIM 1 // iOS, tvOS, or watchOS Simulator #elif TARGET_OS_MACCATALYST #define _OS_APPLE_CATA 1 // Mac's Catalyst (ports iOS API into Mac, like UIKit). #elif TARGET_OS_IPHONE #define _OS_APPLE_PHO 1 // iOS, tvOS, or watchOS device #elif TARGET_OS_MAC #define _OS_APPLE_MAC 1 // Other kinds of Apple platforms #else # error "Unknown Apple platform" #endif #elif __linux__ #define _OS_LINUX 1 // linux #elif __unix__ // all unices not caught above #define _OS_UNIX 1 // Unix #elif defined(_POSIX_VERSION) #define _OS_POSIX 1 // POSIX #else # error "Unknown compiler" #endif #if _OS_WIN #define WIN_PART 1 #elif _OS_LINUX #define LINUX_PART 1 #else #error "Not Supported Operator System" #endif #if WIN_PART #include #include #include #define strcasecmp _stricmp #define strncasecmp _strnicmp #define socklen_t int #elif LINUX_PART #include #include #include #include #define SOCKET long long int //#define INVALID_SOCKET (SOCKET)(~0) #endif #ifndef ZZY_SLEEP #define ZZY_SLEEP #if WIN_PART #define sleeps(s) Sleep(s*1000) #define sleepms(ms) Sleep(ms) #elif LINUX_PART #define sleeps(s) sleep(s) #define sleepms(ms) usleep(ms*1000) #endif #endif #ifdef __cplusplus extern "C" { #endif enum { ERR_SOCK_SUCCESS, ERR_SOCK_MALLOC, ERR_SOCK_NULLPTR, ERR_SOCK_WSAStartup, ERR_SOCK_DETERMINE_AGREEMENT, ERR_SOCK_CREATE_SOCKET, ERR_SOCK_BIND, ERR_SOCK_LISTEN, ERR_SOCK_ACCEPT, 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, }; static inline int make_sock(SOCKET* sock); static inline int sock_connect(SOCKET sock, const char* connect_ip, unsigned short port); static inline int sock_bindlisten(SOCKET sock, const char* server_ip, unsigned short port); static inline int sock_accpet(SOCKET sock,SOCKET* client, char** accept_ip, unsigned short* port); static inline int make_server_sock(SOCKET* sock, const char* server_ip, unsigned short port); static inline int make_client_sock(SOCKET* sock, const char* connect_ip, unsigned short port); static inline void close_sock(SOCKET sock); 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 sock_thread(void(*thread_func)(void*), void* data); #define _SOCKET_TEST_IP "127.0.0.1" #define _SOCKET_TEST_PORT 6789 static inline int _socket(SOCKET* sock, const char* ip, const char* port); static inline int _connect(SOCKET sock, const char* ip, const char* port); static inline int _bind(SOCKET sock, const char* ip, const char* port); static inline int _bindlisten(SOCKET sock, const char* ip, const char* port); static inline int _sock(SOCKET* sock, int af, int type); static inline int make_sock(SOCKET* sock) { return make_sock_tcp4(sock); }; static inline int make_sock_tcp4(SOCKET* sock) { return _sock(sock, AF_INET, 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_udp6(SOCKET* sock) { return _sock(sock, AF_INET6, SOCK_DGRAM); } static inline int _sock(SOCKET* sock, int af, int type) { #ifdef WIN_PART WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { return ERR_SOCK_WSAStartup; } if (HIBYTE(wsaData.wVersion) != 2 || \ LOBYTE(wsaData.wVersion) != 2) { return ERR_SOCK_DETERMINE_AGREEMENT; } #endif *sock = socket(af, type, 0); if (*sock == INVALID_SOCKET) { return ERR_SOCK_CREATE_SOCKET; } return ERR_SOCK_SUCCESS; } static inline int _sock_eai_res_map(int res) { switch (res) { case EAI_AGAIN: return ERR_SOCK_EAI_AGAIN; case EAI_BADFLAGS: return ERR_SOCK_EAI_BADFLAGS; case EAI_FAIL: return ERR_SOCK_EAI_FAIL; case EAI_FAMILY: return ERR_SOCK_EAI_FAMILY; case EAI_MEMORY: return ERR_SOCK_EAI_MEMORY; case EAI_NONAME: return ERR_SOCK_EAI_NONAME; case EAI_SERVICE: return ERR_SOCK_EAI_SERVICE; case EAI_SOCKTYPE: return ERR_SOCK_EAI_SOCKTYPE; default: return ERR_SOCK_EAI_MAPPING_NOT_EXIST; } } static inline int _socket(SOCKET* sock, const char* ip, const char* port) { struct addrinfo inf = { 0 }; struct addrinfo* res_addr = NULL; int res = getaddrinfo(ip, port, &inf, &res_addr); if (res != 0) { return _sock_eai_res_map(res); } 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 == INVALID_SOCKET) { return ERR_SOCK_CREATE_SOCKET; } freeaddrinfo(res_addr); return ERR_SOCK_SUCCESS; } } freeaddrinfo(res_addr); return ERR_SOCK_CONNECT; } static inline int _connect(SOCKET sock, const char* ip, const char* port) { struct addrinfo inf = { 0 }; struct addrinfo* res_addr = NULL; int res = getaddrinfo(ip, port, &inf, &res_addr); if (res != 0) { return _sock_eai_res_map(res); } for (struct addrinfo* p = res_addr; p != NULL; p = p->ai_next) { if (connect(sock, p->ai_addr, p->ai_addrlen) == 0) { freeaddrinfo(res_addr); return ERR_SOCK_SUCCESS; } } freeaddrinfo(res_addr); return ERR_SOCK_CONNECT; } static inline int _bind(SOCKET sock, const char* ip, const char* port) { struct addrinfo inf = { 0 }; struct addrinfo* res_addr = NULL; int res = getaddrinfo(ip, port, &inf, &res_addr); if (res != 0) { return ERR_SOCK_ADDRINFO; } for (struct addrinfo* p = res_addr; p != NULL; p = p->ai_next) { if (bind(sock, p->ai_addr, p->ai_addrlen) == 0) { freeaddrinfo(res_addr); return ERR_SOCK_SUCCESS; } } freeaddrinfo(res_addr); return ERR_SOCK_CONNECT; } static inline int _bindlisten(SOCKET sock, const char* ip, const char* port) { int res = _bind(sock, ip, port); if(res == ERR_SOCK_SUCCESS){ if (listen(sock, SOMAXCONN) == 0) { return ERR_SOCK_SUCCESS; } return ERR_SOCK_LISTEN; } return res; } static inline int sock_connect(SOCKET sock, const char* connect_ip, unsigned short port) { char buf[8] = { 0 }; sprintf(buf, "%u", port); return _connect(sock, connect_ip, buf); } static inline int sock_bindlisten(SOCKET sock, const char* server_ip, unsigned short port) { char buf[8] = { 0 }; sprintf(buf, "%u", port); return _bindlisten(sock, server_ip, buf); } static inline int sock_accpet(SOCKET sock,SOCKET* client, char** accept_ip, unsigned short* port) { struct sockaddr_in caddr = { 0 }; socklen_t addrLen = sizeof(struct sockaddr_in); if(client == NULL) { return ERR_SOCK_NULLPTR; } *client = accept(sock,(struct sockaddr*) &caddr, &addrLen); if (*client == -1) { return ERR_SOCK_ACCEPT; } char* ip = (char*)malloc(32); if(ip == NULL) { return ERR_SOCK_MALLOC; } int buffLen = strlen( inet_ntoa(caddr.sin_addr) ); if(accept_ip != NULL) { strncpy(ip, inet_ntoa(caddr.sin_addr), buffLen); ip[buffLen] = '\0'; *accept_ip = ip; } if(port != NULL) { *port = ntohs(caddr.sin_port); } return ERR_SOCK_SUCCESS; } static inline int make_server_sock(SOCKET* sock, const char* server_ip, unsigned short port) { int res = make_sock(sock); if(res != ERR_SOCK_SUCCESS) { return res; } res = sock_bindlisten(*sock, server_ip, port); if(res != ERR_SOCK_SUCCESS) { return res; } return ERR_SOCK_SUCCESS; } static inline int make_client_sock(SOCKET* sock, const char* connect_ip, unsigned short port) { int res = make_sock(sock); if(res != ERR_SOCK_SUCCESS) { return res; } if(connect_ip) { res = sock_connect(*sock, connect_ip, port); if(res != ERR_SOCK_SUCCESS) { return res; } } return ERR_SOCK_SUCCESS; } static inline void close_sock(SOCKET sock) { if(sock == -1) { return; } #if WIN_PART closesocket(sock); #elif LINUX_PART close(sock); #endif } static inline void out_sock_err(FILE* output, int errcode) { fprintf(output, "%d", errcode); } static inline void get_sock_err(char* buff_128, size_t buff_len, int errcode) { if(buff_len < 128) { return; } // enum { // ERR_SOCK_SUCCESS, // ERR_SOCK_MALLOC, // ERR_SOCK_NULLPTR, // ERR_SOCK_WSAStartup, // ERR_SOCK_DETERMINE_AGREEMENT, // ERR_SOCK_CREATE_SOCKET, // ERR_SOCK_BIND, // ERR_SOCK_LISTEN, // ERR_SOCK_ACCEPT, // ERR_SOCK_CONNECT, // }; //https://learn.microsoft.com/zh-cn/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo?redirectedfrom=MSDN //错误值 WSA 等效项 说明 //EAI_AGAIN WSATRY_AGAIN 名称解析暂时失败。 //EAI_BADFLAGS WSAEINVAL 为 pHints 参数的 ai_flags 成员提供了无效值。 //EAI_FAIL WSANO_RECOVERY 名称解析中发生不可恢复的失败。 //EAI_FAMILY WSAEAFNOSUPPORT 不支持 pHints 参数的 ai_family 成员。 //EAI_MEMORY WSA_NOT_ENOUGH_MEMORY 内存分配失败。 //EAI_NONAME WSAHOST_NOT_FOUND 所提供的参数的名称未解析,或者未提供 pNodeName 和 pServiceName 参数。 //EAI_SERVICE WSATYPE_NOT_FOUND pHints 参数的指定ai_socktype成员不支持 pServiceName 参数。 //EAI_SOCKTYPE WSAESOCKTNOSUPPORT 不支持 pHints 参数的 ai_socktype 成员。 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 } #endif #endif