zoukankan      html  css  js  c++  java
  • 实现一个跨平台的mysock库(windows、linux)

    

    源码下载


    1.首先确定自己的操作系统为32位还是64位:

    root@bfq:~/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.编写測试程序:

    root@bfq:~/mysock# vim test.c

     

    #include <stdio.h>
    
     
    
    int main()
    
    {
    
            printf("sizeof(char *)=%d
    ",sizeof(char *));
    
            return 0;
    
    }
    

    编译、运行:

    root@bfq:~/mysock# gcc test.c

    root@bfq:~/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

    root@bfq:~/mysock# ./a.out

    sizeof(char *)=8

     

    root@bfq:~/mysock# gcc test.c-m32

    root@bfq:~/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

    root@bfq:~/mysock# ./a.out

    sizeof(char *)=4

     使用-m32来使得gcc编译32位程序(在x86_64系统上),使用-m elf_i386參数可以使得64位的ld可以兼容32位的库 

     

    3.跨平台代码分析

    编译:

    root@bfq:~/mysock#ls

    libmysock64.so makefile-lib32 makefile-lib64  makefile-win mysock.c  mysock.h

    root@bfq:~/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

    root@bfq:~/mysock#file libmysock32.so

    libmysock32.so:ELF32-bit LSB shared object, Intel 80386,version 1 (SYSV), dynamically linked,BuildID[sha1]=0x18b8a6de746679cccfb10306d6bc62955e3566f4, not stripped

    root@bfq:~/mysock#

     

    root@bfq:~/mysock#make -f makefile-lib64

    gcc-Wall -D__UNIX -g -fPIC -o mysock.o -c mysock.c

    gcc-shared -o libmysock64.so mysock.o

    root@bfq:~/mysock#ls

    libmysock64.so makefile-lib32 makefile-lib64  makefile-win mysock.c  mysock.h mysock.o

    root@bfq:~/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 $@ -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 $@ -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);
    }
    
    
    


    
  • 相关阅读:
    SSL certificate verify failed” using pip to install packages
    Getting The following errors when installing boto3
    D3 Scale functions
    Making a simple scatter plot with d3.js
    Basic scatterplot in d3.js
    D3 Tick Format
    CentOS定时备份mysql数据库和清理过期备份文件
    linux yum清除var目录下缓存的方法
    正则表达式纯数字校验
    每天一个Linux命令--查看当前登陆用户并强制退出
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5360336.html
Copyright © 2011-2022 走看看