实现一个跨平台的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)的主要内容,如果未能解决你的问题,请参考以下文章

连接服务器的客户端IP

TBOX | 一个用c语言实现的跨平台开发库

使用 Kotlin 多平台实现相机库

跨平台 Nuget 库

静态库和动态库的区别和win平台和linux平台代码实现

基于canvas实现的高性能跨平台的股票图表库--clchart