实现一个跨平台的mysock库(windowslinux)
Posted phlsheji
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现一个跨平台的mysock库(windowslinux)相关的知识,希望对你有一定的参考价值。
源码下载
1.首先确定自己的操作系统为32位还是64位:
[email protected]:~/mysock# uname -a
Linux bfq 3.11.0-26-generic#45~precise1-Ubuntu SMP Tue Jul 15 04:02:35 UTC 2014x86_64x86_64 x86_64 GNU/Linux
2.编写測试程序:
[email protected]:~/mysock# vim test.c
#include <stdio.h> int main() { printf("sizeof(char *)=%d\n",sizeof(char *)); return 0; }
编译、运行:
[email protected]:~/mysock# gcc test.c
[email protected]:~/mysock# file a.out
a.out: ELF64-bitLSB executable, x86-64, version 1 (SYSV), dynamically linked (uses sharedlibs), for GNU/Linux 2.6.24,BuildID[sha1]=0x69d02236045c81b597e24cb143cfca5909987b80, not stripped
[email protected]:~/mysock# ./a.out
sizeof(char *)=8
[email protected]:~/mysock# gcc test.c-m32
[email protected]:~/mysock# file a.out
a.out: ELF32-bitLSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses sharedlibs), for GNU/Linux 2.6.24,BuildID[sha1]=0x668431a373c94667857a83c2d92929e8b57cff58, not stripped
[email protected]:~/mysock# ./a.out
sizeof(char *)=4
使用-m32来使得gcc编译32位程序(在x86_64系统上),使用-m elf_i386參数可以使得64位的ld可以兼容32位的库
3.跨平台代码分析
编译:
[email protected]:~/mysock#ls
libmysock64.so makefile-lib32 makefile-lib64 makefile-win mysock.c mysock.h
[email protected]:~/mysock#make -f makefile-lib32
gcc-Wall -D__UNIX -g -m32 -fPIC -o mysock.o -c mysock.c
gcc -m32 -shared -o libmysock32.so mysock.o
[email protected]:~/mysock#file libmysock32.so
libmysock32.so:ELF32-bit LSB shared object, Intel 80386,version 1 (SYSV), dynamically linked,BuildID[sha1]=0x18b8a6de746679cccfb10306d6bc62955e3566f4, not stripped
[email protected]:~/mysock#
[email protected]:~/mysock#make -f makefile-lib64
gcc-Wall -D__UNIX -g -fPIC -o mysock.o -c mysock.c
gcc-shared -o libmysock64.so mysock.o
[email protected]:~/mysock#ls
libmysock64.so makefile-lib32 makefile-lib64 makefile-win mysock.c mysock.h mysock.o
[email protected]:~/mysock#file libmysock64.so
libmysock64.so:ELF64-bit LSB shared object, x86-64, version 1(SYSV), dynamically linked,BuildID[sha1]=0xbec5736775c33f27fe81e88c98f1c26a1edf97b9, not stripped
源代码结构:
linux
windows
各种平台的makefile
.SUFFIXES: .c .o CC=gcc SRCS=mysock.c OBJS=$(SRCS:.c=.o) EXEC=libmysock64.so .c.o: $(CC) -Wall -D__UNIX -g -fPIC -o [email protected] -c $< all: $(OBJS) $(CC) -shared -o $(EXEC) $(OBJS) clean: rm -rf $(OBJS) $(EXEC)
.SUFFIXES: .c .o CC=gcc SRCS=mysock.c OBJS=$(SRCS:.c=.o) EXEC=libmysock32.so .c.o: $(CC) -Wall -D__UNIX -g -m32 -fPIC -o [email protected] -c $< all: $(OBJS) $(CC) -m32 -shared -o $(EXEC) $(OBJS) clean: rm -rf $(OBJS) $(EXEC)
利用vs开发工具本身能够编译出lib和dll。
mysock.h
#ifndef __MYSOCK_H #define __MYSOCK_H #ifdef __cplusplus extern "C" { #endif //linux下设置进程进入daemon状态。windows无效 void set_daemon(); //windows下调用的初始化socket环境。linux不须要 void init_socket(); //windows下调用的释放socket环境。linux不须要 void free_socket(); //将域名转化为IP,domain代表域名,返回值为struct in_addr的s_addr成员 unsigned int domain2ip(const char *domain); //建立一个socket。 //status = 1 is TCP, other is UDP。返回值>=0代表成功建立的socket句柄。-1失败 int create_socket(int status); //关闭由create_socket创建的socket, //sock为create_socket函数返回的socket句柄 void close_socket(int sock); //为socket绑定一个端口号 //sock为create_socket函数返回的socket句柄。port为要绑定的端口号。返回值=0成功。-1失败 int bind_socket(int sock, unsigned short port); //使用UDP协议接收数据 //sock为create_socket函数返回的socket句柄,buf为接收数据缓冲区。 bufsize为缓冲区大小(单位:字节), srcIP为数据来源IP地址。返回值>0成功接收数据字节数,=0连接正常关闭,-1失败 int udp_recv(int sock, char *buf, size_t bufsize, char *srcIP); //使用UDP协议发送数据 //sock为create_socket函数返回的socket句柄。buf为发送数据缓冲区。 bufsize为发送数据大小(单位:字节)。destIP为发送目的IP地址,port为发送目的端口号 。返回值>0成功发送数据字节数,=0连接正常关闭,-1失败 int udp_send(int sock, const char *destIP, unsigned short port, const char *buf, size_t bufsize); //使用TCP协议接收数据之前须要先listen //sock为create_socket函数返回的socket句柄。返回值=0成功,-1失败 int tcp_listen(int sock); //使用TCP协议接收来自client的链接 //sock为create_socket函数返回的socket句柄, srcIP为来自client的IP地址。返回值>0代表来自client的socket句柄,-1失败 int tcp_accept(int sock, char *srcIP); //使用TCP协议连接到指定的服务器 //sock为create_socket函数返回的socket句柄,destIP为来自服务端端的IP地址。port为服务端的端口号。返回值=0成功,-1失败 int tcp_connect(int sock, const char *destIP, unsigned short port); //使用TCP协议接收数据 //sock为create_socket函数返回的socket句柄。buf为接收数据缓冲区。 bufsize为缓冲区大小(单位:字节)。返回值>0成功接收数据字节数。=0连接正常关闭,-1失败 int tcp_recv(int sock, char *buf, size_t bufsize); //使用TCP协议发送数据 //sock为create_socket函数返回的socket句柄,buf为发送数据缓冲区。 bufsize为发送数据大小哦(单位:字节)。返回值>0成功发送数据字节数,=0连接正常关闭,-1失败 int tcp_send(int sock, const char *buf, size_t bufsize); ////////////////////////////////下面为app函数////////////////////////// //使用UDP协议接收数据 //buf为接收数据缓冲区, bufsize为缓冲区大小(单位:字节), port为接收数据的端口号,srcIP为数据来源IP地址。返回值>0成功接收数据字节数。=0连接正常关闭。-1失败 int app_udp_recv(char *buf, size_t bufsize, unsigned short port, char *srcIP); //使用UDP协议发送数据 //buf为发送数据缓冲区。 bufsize为发送数据大小(单位:字节),destIP为发送目的IP地址,port为发送目的端口号 。返回值>0成功发送数据字节数,=0连接正常关闭。-1失败 int app_udp_send(const char *destIP, unsigned short port, const char *buf, size_t bufsize); //使用TCP协议client连接到指定的服务端 //destIP为来自服务端的IP地址,port为服务端的端口号。返回值=0成功,-1失败 int app_client_connect(const char *destIP, unsigned short port); //断开clientTCP连接 void app_client_close(); //断开服务端TCP连接 void app_server_close(); //使用TCP协议client接收数据 //buf为接收数据缓冲区。bufsize为缓冲区大小(单位:字节)。返回值>0成功接收数据字节数,=0连接正常关闭。-1失败 int app_client_recv(char *buf, size_t bufsize); //使用TCP协议client发送数据 //buf为发送数据缓冲区。 bufsize为发送数据大小哦(单位:字节)。返回值>0成功发送数据字节数,=0连接正常关闭,-1失败 int app_client_send(const char *buf, size_t bufsize); //使用TCP协议。建立服务端socket //參数port为服务端端口号,返回值=0成功,-1失败 int app_server_create(unsigned short port); //使用TCP协议服务端接收数据 //buf为接收数据缓冲区。bufsize为缓冲区大小(单位:字节),srcIP为clientIP地址。
返回值>0成功接收数据字节数。=0连接正常关闭。-1失败 int app_server_recv(char *buf, size_t bufsize, char *srcIP); //使用TCP协议服务端发送数据 //buf为发送数据缓冲区, bufsize为发送数据大小哦(单位:字节)。返回值>0成功发送数据字节数。=0连接正常关闭,-1失败 int app_server_send(const char *buf, size_t bufsize); #ifdef __cplusplus } #endif #endif
mysock.c
#include <string.h> #include <stdlib.h> #include <stdio.h> #ifndef __UNIX #include <WinSock2.h> #pragma comment(lib, "Ws2_32.lib") #pragma warning(disable:4996) #else #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h> #endif //假设编译动态库。须要把#define STATIC_LIB凝视 #define STATIC_LIB #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif void set_daemon() { #ifdef __UNIX pid_t pid, sid; pid = fork(); if (pid < 0) { exit(-1); } if (pid > 0) { exit(0); } if ((sid = setsid()) < 0) { exit(-1); } #endif } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif void init_socket() { #ifndef __UNIX unsigned short ver; WSADATA wsaData; ver = MAKEWORD(1, 1); WSAStartup(ver, &wsaData); #endif } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif void free_socket() { #ifndef __UNIX WSACleanup(); #endif } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif unsigned int domain2ip(const char *domain) { struct hostent *iphost = gethostbyname(domain); if (iphost) { struct in_addr *p = (struct in_addr *)iphost->h_addr_list[0]; if (p) return p->s_addr; } return 0; } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int create_socket(int status) { #ifndef __UNIX char on = 1; #else int on = 1; #endif int st = 0; if (status == 1) { st = socket(AF_INET, SOCK_STREAM, 0);//建立TCP socket setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));//设置socket地址可重用 } else { st = socket(AF_INET, SOCK_DGRAM, 0);//建立UDP socket setsockopt(st, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));//设置能够发送udp广播消息 } return st; } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif void close_socket(int sock) { #ifndef __UNIX closesocket(sock); #else close(sock); #endif } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int bind_socket(int sock, unsigned short port) { struct sockaddr_in recv_addr; memset(&recv_addr, 0, sizeof(recv_addr)); recv_addr.sin_family = AF_INET; recv_addr.sin_port = htons(port);//指定port为要连接的端口号 recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//指定接收端IP地址为随意 return bind(sock, (struct sockaddr *) &recv_addr, sizeof(recv_addr)); } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int udp_recv(int sock, char *buf, size_t bufsize, char *srcIP) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); #ifndef __UNIX int len = sizeof(addr); #else socklen_t len = sizeof(addr); #endif unsigned int rc = recvfrom(sock, buf, bufsize, 0, (struct sockaddr *) &addr, &len);//接收到来自srcIP的消息 //strcpy(srcIP, inet_ntoa(addr.sin_addr)); unsigned char *c = (unsigned char *)&addr.sin_addr.s_addr; sprintf(srcIP, "%u.%u.%u.%u", c[0], c[1], c[2], c[3]); return rc; } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int udp_send(int sock, const char *destIP, unsigned short port, const char *buf, size_t bufsize) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port);//指定port为要连接的端口号 //addr.sin_addr.s_addr = inet_addr(destIP);//指定IP为要连接的IP地址 addr.sin_addr.s_addr = domain2ip(destIP); return sendto(sock, buf, bufsize, 0, (struct sockaddr *) &addr, sizeof(addr));//向指定IP发送消息 } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int tcp_listen(int sock) { return listen(sock, 20); } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int tcp_accept(int sock, char *srcIP) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); #ifndef __UNIX int len = sizeof(addr); #else socklen_t len = sizeof(addr); #endif int st = accept(sock, (struct sockaddr *) &addr, &len); //strcpy(srcIP, inet_ntoa(addr.sin_addr)); unsigned char *c = (unsigned char *)&addr.sin_addr.s_addr; sprintf(srcIP, "%u.%u.%u.%u", c[0], c[1], c[2], c[3]); return st; } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int tcp_connect(int sock, const char *destIP, unsigned short port) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port);//指定port为要连接的端口号 //addr.sin_addr.s_addr = inet_addr(destIP);//指定IP为要连接的IP地址 addr.sin_addr.s_addr = domain2ip(destIP); return connect(sock, (struct sockaddr *) &addr, sizeof(addr));//连接到指定IP } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int tcp_recv(int sock, char *buf, size_t bufsize) { return recv(sock, buf, bufsize, 0); } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int tcp_send(int sock, const char *buf, size_t bufsize) { return send(sock, buf, bufsize, 0); } ////////////////////////////////下面为app函数////////////////////////// static int is_init = 0; static int udp_recv_sock = -1; static int udp_send_sock = -1; static int tcp_client_sock = -1; static int tcp_server_sock = -1; static int tcp_list_sock = -1; #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int app_udp_recv(char *buf, size_t bufsize, unsigned short port, char *srcIP) { if (is_init == 0) { init_socket(); is_init = 1; } if (udp_recv_sock != -1) close_socket(udp_recv_sock); udp_recv_sock = create_socket(0); int rc = bind_socket(udp_recv_sock, port); if (rc < 0) return rc; return udp_recv(udp_recv_sock, buf, bufsize, srcIP); } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int app_udp_send(const char *destIP, unsigned short port, const char *buf, size_t bufsize) { if (is_init == 0) { init_socket(); is_init = 1; } if (udp_send_sock == -1) { udp_send_sock = create_socket(0); } return udp_send(udp_send_sock, destIP, port, buf, bufsize); } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int app_client_connect(const char *destIP, unsigned short port) { if (is_init == 0) { init_socket(); is_init = 1; } if (tcp_client_sock != -1) close_socket(tcp_client_sock); tcp_client_sock = create_socket(1); return tcp_connect(tcp_client_sock, destIP, port); } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif void app_client_close() { if (tcp_client_sock != -1) { close_socket(tcp_client_sock); tcp_client_sock = -1; } } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif void app_server_close() { if (tcp_server_sock != -1) { close_socket(tcp_server_sock); tcp_server_sock = -1; } } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int app_client_recv(char *buf, size_t bufsize) { return tcp_recv(tcp_client_sock, buf, bufsize); } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int app_client_send(const char *buf, size_t bufsize) { return tcp_send(tcp_client_sock, buf, bufsize); } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int app_server_create(unsigned short port) { if (is_init == 0) { init_socket(); is_init = 1; } if (tcp_list_sock != -1) { close_socket(tcp_list_sock); } tcp_list_sock = create_socket(1); int rc = bind_socket(tcp_list_sock, port); if (rc == -1) return rc; return tcp_listen(tcp_list_sock); } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int app_server_recv(char *buf, size_t bufsize, char *srcIP) { static char IP[100]; if (tcp_server_sock <= 0) { memset(IP, 0, sizeof(IP)); tcp_server_sock = tcp_accept(tcp_list_sock, IP); } strcpy(srcIP, IP); int rc = tcp_recv(tcp_server_sock, buf, bufsize); if (rc <= 0) app_server_close(); return rc; } #ifndef __UNIX #ifndef STATIC_LIB __declspec(dllexport) #endif #endif int app_server_send(const char *buf, size_t bufsize) { return tcp_send(tcp_server_sock, buf, bufsize); }
以上是关于实现一个跨平台的mysock库(windowslinux)的主要内容,如果未能解决你的问题,请参考以下文章