您的位置:首页 > 运维架构 > Linux

Linux下代码移植及混合编程

2018-02-12 12:28 459 查看
Windows下udp编程

Linux下C编程
makefile

udp程序移植到Linux

cc 混合编程so库文件的编写
混合编程头文件编写

so库的编写

Windows下udp编程

#include <winsock2.h>
#include <string.h>
#include <stdio.h>

int socket_send(const char * ip)
{
// socket version
DWORD version;
// windows socket asynchronous data
WSADATA wsaData;
version = MAKEWORD(1,1);
// init socket
WSAStartup(version,&wsaData);

// define socket object
int af = AF_INET;      // TCP/IP protocol
int type = SOCK_DGRAM; // UDP protocol
int protocol = 0;      // default
SOCKET st = socket(af,type,protocol);

struct sockaddr_in addr;
memset(&addr,0,sizeof(addr)); // set null
addr.sin_family = AF_INET;    // TCP/IP protocol address
addr.sin_port = htons(8080);  // set port,function htons():HOST TO NET SHORT
addr.sin_addr.S_un.S_addr = inet_addr(ip/*"127.0.0.1"*/); // set ip

// send message
printf("enter a message and start communite,end up with char * \n");
int rc = 0;
char buffer[1024] = {0};
while(1)
{
memset(buffer,0,sizeof(buffer));
gets(buffer);
//strcpy(buffer,"hello socket");
if(buffer[0]=='*')
break;
rc = sendto(st,buffer,strlen(buffer),0,(struct sockaddr *)&addr,sizeof(addr));
//test:printf("rc:%d,buffer:%s,to:%s\n",rc,buffer,inet_ntoa(addr.sin_addr));
}

// release resource
closesocket(st);
WSACleanup();

return rc;
}

int socket_receive()
{
// socket version
DWORD version;
// windows socket asynchronous data
WSADATA wsaData;
version = MAKEWORD(1,1);
// init socket
WSAStartup(version,&wsaData);

// define socket object
int af = AF_INET;      // TCP/IP protocol
int type = SOCK_DGRAM; // UDP protocol
int protocol = 0;      // default
SOCKET st = socket(af,type,protocol);

struct sockaddr_in addr;
memset(&addr,0,sizeof(addr)); // set null
addr.sin_family = AF_INET;    // TCP/IP protocol address
addr.sin_port = htons(8080);  // set port,function htons():HOST TO NET SHORT
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // ANY ip could be address as a receiver

// bind socket and addr
if(-1==bind(st,(struct sockaddr *)&addr,sizeof(addr))){
printf("socket bind error!\n");
return 0;
}

// receive message
int rc = 0;
char buffer[1024] = {0};
struct sockaddr_in fromAddr; // sender addr information
memset(&addr,0,sizeof(fromAddr));
int len = sizeof(fromAddr);
while(1)
{
memset(buffer,0,sizeof(buffer));
rc = recvfrom(st,buffer,sizeof(buffer),0,(struct sockaddr *)&fromAddr,&len);
if(rc > 0 ){
printf("%s:%s\n",inet_ntoa(fromAddr.sin_addr),buffer);
}
}

// release resource
closesocket(st);
WSACleanup();

return rc;
}


QT项目下,在profile中需要添加lib,用于链接

LIBS += -l ws2_32

Linux下C编程

makefile

### 常用makefile

# makefile主要有变量、标号(默认执行第一个标号)、指令(指令必须以TAB开头)、依赖

# 变量,使用变量 $(变量名)
CC = g++

SRCS = main.cpp\
myudp.cpp

#相应变量间的替换字符
OBJS = $(SRCS:.cpp=.o)

EXEC = myapp

start:$(OBJS)
$(CC) -o $(EXEC) $(OBJS)

.cpp.o:
#本例中,在linux下使用该makefile编译,编译时定义宏OS_LINUX
$(CC) -o $@ -c $< -D OS_LINUX

clean:
#删除编译中间文件
rm -rf $(OBJS)


### 编译库文件的makefile

CC = gcc

SRCS = myfunc.c

OBJS = $(SRCS:.c=.o)

EXEC = libmyfunc.so

start:$(OBJS)
$(CC) -o $(EXEC) $(OBJS) -shared

.c.o:
$(CC) -o $@ -c $< -fPIC

clean:
rm -rf $(OBJS)


### 链接库文件的应用的makefile

CC = g++

SRCS = main.cpp

OBJS = $(SRCS:.cpp=.o)

EXEC = myapp

start:$(OBJS)
$(CC) -o $(EXEC) $(OBJS) -L . -l myfunc

.cpp.o:
$(CC) -o $@ -c $<

clean:
rm -rf $(OBJS)


udp程序移植到Linux

// 利用宏使得当前源码可在linux与window下都能执行
#include <string.h>
#include <stdio.h>

#ifndef OS_LINUX
//当前在window下
#include <winsock2.h>
#define SOCKLEN_T int

#else
//当前在linux下
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>

#define SOCKET int
#define SOCKLEN_T socklen_t

#endif

int socket_send(const char * ip)
{
#ifndef OS_LINUX
// socket version
DWORD version;
// windows socket asynchronous data
WSADATA wsaData;
version = MAKEWORD(1,1);
// init socket
WSAStartup(version,&wsaData);
#endif

// define socket object
int af = AF_INET;      // TCP/IP protocol
int type = SOCK_DGRAM; // UDP protocol
int protocol = 0;      // default
SOCKET st = socket(af,type,protocol);

struct sockaddr_in addr;
memset(&addr,0,sizeof(addr)); // set null
addr.sin_family = AF_INET;    // TCP/IP protocol address
addr.sin_port = htons(8080);  // set port,function htons():HOST TO NET SHORT
addr.sin_addr.s_addr = inet_addr(ip/*"127.0.0.1"*/); // set ip

// send message
printf("enter a message and start communite,end up with char * \n");
int rc = 0;
char buffer[1024] = {0};
while(1)
{
memset(buffer,0,sizeof(buffer));
fgets(buffer,1024,stdin);
//strcpy(buffer,"hello socket");
if(buffer[0]=='*')
break;
rc = sendto(st,buffer,strlen(buffer),0,(struct sockaddr *)&addr,sizeof(addr));
//test:printf("rc:%d,buffer:%s,to:%s\n",rc,buffer,inet_ntoa(addr.sin_addr));
}
#ifndef OS_LINUX
//当前在window下
closesocket(st);
WSACleanup();
#else
//当前在linux下
close(st);

#endif

return rc;
}

int socket_receive()
{
#ifndef OS_LINUX
// socket version
DWORD version;
// windows socket asynchronous data
WSADATA wsaData;
version = MAKEWORD(1,1);
// init socket
WSAStartup(version,&wsaData);
#endif

// define socket object
int af = AF_INET;      // TCP/IP protocol
int type = SOCK_DGRAM; // UDP protocol
int protocol = 0;      // default
SOCKET st = socket(af,type,protocol);

struct sockaddr_in addr;
memset(&addr,0,sizeof(addr)); // set null
addr.sin_family = AF_INET;    // TCP/IP protocol address
addr.sin_port = htons(8080);  // set port,function htons():HOST TO NET SHORT
addr.sin_addr.s_addr = htonl(INADDR_ANY); // ANY ip could be address as a receiver

// bind socket and addr
if(-1==bind(st,(struct sockaddr *)&addr,sizeof(addr))){
printf("socket bind error!\n");
return 0;
}

// receive message
int rc = 0;
char buffer[1024] = {0};
struct sockaddr_in fromAddr; // sender addr information
memset(&addr,0,sizeof(fromAddr));
SOCKLEN_T len = sizeof(fromAddr);
while(1)
{
memset(buffer,0,sizeof(buffer));
rc = recvfrom(st,buffer,sizeof(buffer),0,(struct sockaddr *)&fromAddr,&len);
if(rc > 0 ){
printf("%s:%s\n",inet_ntoa(fromAddr.sin_addr),buffer);
}
}

#ifndef OS_LINUX
//当前在window下
closesocket(st);
WSACleanup();
#else
//当前在linux下
close(st);

#endif

return rc;
}


Linux和Windows在使用udp编程上的差异(移植关键)主要有:

SOCKET类型是windows定义,linux下为int类型

由于历史原因,windows对于udp的支持为外挂形式,需要手动启动资源、关闭资源,linux无须,可用宏解决该问题

关闭socket的函数不同,windows下为closesocket(SOCKET),linux下为close(int)

htons函数头文件不同,linux下可用man查看该函数头文件,包括查看socket相关头文件。

win下需要头文件

c\c++ 混合编程、so库文件的编写

混合编程头文件编写

原理(c++调用c代码):

C++函数具有继承重载等面向对象特性,在预编译时,预编译器对函数名有处理,而C的函数在预编译时函数名不会做改变(通过编译器 -E选项可以看到结果)。所以.cpp文件调用a.c文件的函数会出现函数未定义的情况,此时可在a.c文件对应的头文件a.h中对a.c文件的函数做显示的声明(extern “C”{ func1 func2 … })。

但上述处理同样会出现一个问题,就是a.c文件只能被.cpp文件调用,如果现在同时需要一个b.c文件调用a.c函数,那么extern “C” 会被gcc编译器视为非法语句。

解决办法用宏定义,如下代码:

#ifndef LIBMYFUNC_H
#define LIBMYFUNC_H

/*
此处__cplusplus是g++在编译cpp文件时默认定义的宏
原因是:c++文件引用c文件的函数时,对于函数的编译方式不同(涉及重载等)所以需要指明是c的函数,extern “C”作用及此
而c文件引用该函数时,extern “c” 在c语句中不合法。
故要根据实际情况,利用__cplusplus宏区分
*/

#ifdef __cplusplus
extern "C"
{
#endif
int max(int a,int b);
#ifdef __cplusplus
}
#endif

#endif


so库的编写

Linux中库文件总是以libxxxx.so的固定格式出现,故编译链接输出的文件名需要是该格式

g++ 在编译生成可执行程序时若需要链接库文件,需要添加 -L -l 选项指定库的位置,和库的名称。且库的名称是去掉前后缀lib和.so的文件名,位置默认在系统lib目录,不会在当前目录下寻找。

故通常需要为linux修改环境变量,为库文件的位置环境变量上添加当前目录,同时最好为二进制执行程序也添加当前目录。

可在终端中使用 ldd命令查看执行程序链接的so文件

so文件是动态共享代码,故编译的时候需要添加编译选项 -fPIC,表示该代码是固定入口地址,在系统内存只有一份,供不同应用调用,链接生成so文件时,添加编译选项 -shared。

cd
vi  .profile
# 添加以下两句,Linux中环境变量地址以冒号:分隔
export PATH=$PATH:.
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.


so文件的编译,见上文makefile
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: