linux 系统编程中多半是使用 C 语言以过程式的编程方法来完成整套流程的工作的,
这对于习惯使用面向对象编程的我来说有很多地方不是很习惯。
比如说,编写面向对象代码的时候,总是把类的声明和类中的成员变量和成员函数声明
在头文件中实现,然后在.cpp 文件中只要对头文件中类中声明的成员函数进行实现便可以了。
如果某个工程中需要这个类中的方法,只要引入该类的头文件便可以了。
然而过程式编程中,这种方法并不能够仅仅通过引入头文件的方式就可以将头文件中定义的方法
作为公共方法来使用。
在过程是编程中,往往在头文件中对函数进行声明,然后在.cpp 文件中写出声明的函数的过程实现,
然后将该 .cpp 文件编译成动态库或是静态库,才能够使 .cpp 文件中的函数被其他程序通过引入头文件所使用。
本篇文章中会编写一个应用与 UDP 协议的通信客户端和服务器端,不同于前几篇文章中的是,
为了尽量减少代码的冗余,会将公共的网络通信代码编写到指定的 .cpp 文件中,然后通过不同的编译方法,
将其编译成动态库和静态库,将其引入到客户端和服务器端的程序中进行调用。
现有头文件 udpnet.h , .cpp 文件 udpnet.cpp
1. 创建静态链接库:
通过下面的的命令来创建一个名为 libudpnet.a 的静态链接库,(注意这个地方的命名规则 lib+源文件的名称 .a)
并将该静态链接库拷贝到系统库的搜索路径下面 /usr/lib/ , /usr/lib64/ , /lib/
1.1
[命令] 首先将 udpnet.cpp 编译生成 udpnet.o 目标文件(object)
g++ -o udpnet.o -c udpnet.cpp
[命令执行结果] 在当前的路径下生成 udpnet.o 文件
1.2
[命令] 将 udpnet.o 目标文件转换为静态库文件
ar src libudpnet.a udpnet.o
[命令执行结果] 在当前的路径下生成 libudpnet.a 静态库文件
1.3
[命令] 将生成的静态库文件,拷贝到系统库的目录下面
cp libudpnet.a /lib/libudpnet.a
cp libudpnet.a /usr/lib64/libudpnet.a
cp libudpnet.a /usr/lib/libudpnet.a
使用静态库
现有程序 client.cpp 和 server.cpp
在编译的时候能够通过如下命令来将静态库加载到编译生成的对象中
[命令] 编译生成 server 对象
g++ server.cpp -ludpnet.a -o server
[命令] 编译 client.cpp 代码生成 client 对象
g++ client.cpp -ludpnet.a -o client
实例代码
1. udpnet.h
-
// udpnet.h
-
-
#ifndef UDPNET_H_
-
#define DUPNET_H_
-
-
int getSocketDone () ;
-
-
int getServerBindDone ( int sock_fd ) ;
-
-
int SendMsgTo ( int sock_fd , const char *msg , int msg_len ,
-
const char *to_addr , short port ) ;
-
-
int RecvMsgFrom ( int sock_fd , char *buffer , int *buf_len ,
-
char *from_addr , short *port ) ;
-
-
#endif
2. udpnet.cpp
-
// udpnet.cpp
-
-
#include <stdio.h> // perror
-
#include <string.h> // memset
-
-
#include <sys/types.h> // AF_INET:IP , SOCK_STREAM:TCP , SOCK_DGRAM:UDP
-
#include <sys/socket.h> // socket , bind , sendto , recvfrom
-
#include <netinet/in.h> // sockaddr_in , sockaddr, htons , htonl , ntohs ,ntohl
-
#include <arpa/inet.h> // inet_aton(2) ,inet_ntoa(1)
-
#include <unistd.h> // unix standard library
-
-
#include "udpnet.h"
-
-
#define SERVER_IP "10.0.2.15"
-
#define COMMON_PORT 1027
-
-
int getSocketDone ()
-
{
-
int ret = socket( AF_INET , SOCK_DGRAM , 0 ) ;
-
-
if ( ret < 0 )
-
perror ("socket error") ;
-
-
return ret ;
-
}
-
-
// the following method only be called by server
-
int getServerBindDone ( int sock_fd )
-
{
-
int ret ;
-
struct sockaddr_in serv_addr ;
-
-
memset ( &serv_addr , 0 , sizeof ( struct sockaddr_in ) ) ;
-
serv_addr.sin_family = AF_INET ;
-
serv_addr.sin_port = htons (COMMON_PORT) ;
-
serv_addr.sin_addr.s_addr = htonl (INADDR_ANY) ;
-
-
if ( ( ret = bind ( sock_fd , (struct sockaddr*)&serv_addr ,
-
sizeof(struct sockaddr_in ))) < 0 )
-
perror ("bind error ") ;
-
-
return ret ;
-
-
}
-
-
int SendMsgTo ( int sock_fd , const char *msg , int msg_len ,
-
const char *to_ip , short to_port )
-
{
-
struct sockaddr_in to_addr ;
-
int ret ;
-
-
memset ( &to_addr , 0 , sizeof(struct sockaddr_in )) ;
-
to_addr.sin_family = AF_INET ;
-
to_addr.sin_port = htons (to_port) ;
-
-
if ( ( ret = inet_aton ( to_ip , &to_addr.sin_addr) ) < 0 )
-
{
-
perror ("inet_aton error ") ;
-
return ret ;
-
}
-
-
ret = sendto ( sock_fd , msg , msg_len , 0 ,
-
(struct sockaddr*)&to_addr , sizeof(struct sockaddr_in )) ;
-
-
if ( ret < 0 )
-
perror ( "sendto error ") ;
-
-
return ret ;
-
}
-
-
int RecvMsgFrom ( int sock_fd , char *msg , int *msg_len ,
-
char *from_ip , short *from_port )
-
{
-
int ret , from_len ;
-
struct sockaddr_in from_addr ;
-
-
memset ( &from_addr , 0 , sizeof ( struct sockaddr_in ) ) ;
-
from_len = sizeof ( struct sockaddr_in ) ;
-
-
ret = recvfrom ( sock_fd , msg , (size_t)*msg_len , 0 ,
-
(struct sockaddr*)&from_addr ,(socklen_t*)&from_len ) ;
-
-
if ( ret < 0 )
-
{
-
perror ( "recvfrom error") ;
-
return ret ;
-
}
-
-
*msg_len = strlen ( msg ) ;
-
-
*from_port = ntohs( from_addr.sin_port ) ;
-
-
from_ip = inet_ntoa ( from_addr.sin_addr) ;
-
-
if ( !from_ip ) // from_ip == NULL
-
{
-
perror ("inet_ntoa error") ;
-
return -1 ;
-
}
-
-
return ret ;
-
}
3. client.cpp
-
// client.cpp
-
-
#include <stdio.h> // perror
-
#include <string.h> // memset
-
-
#include <sys/types.h> // AF_INET:IP , SOCK_STREAM:TCP , SOCK_DGRAM:UDP
-
#include <sys/socket.h> // socket , bind , sendto , recvfrom
-
#include <netinet/in.h> // htons , htonl , ntohs , ntohl , sockaddr_in , sockaddr
-
#include <arpa/inet.h> // inet_aton , inet_ntoa
-
#include <unistd.h>
-
-
#include "udpnet.h"
-
-
#define BUFFER_LEN 1024
-
#define IP_LEN 128
-
#define SERVER_IP "10.0.2.15"
-
#define COMMON_PORT 1027
-
-
-
int main ( int c , char **v )
-
{
-
short port ;
-
int ret , sock_fd ;
-
char msg[BUFFER_LEN] , ip_addr[IP_LEN] ;
-
-
if ( ( sock_fd = getSocketDone ()) > 0 )
-
printf ("socket correct fd : %d\n" , sock_fd) ;
-
else
-
goto error ;
-
-
port = COMMON_PORT ;
-
-
memset ( &ip_addr , 0 , sizeof( ip_addr )) ;
-
-
// set server ip address
-
strcpy (ip_addr , SERVER_IP ) ;
-
-
printf ("input message sent to server \n") ;
-
scanf ("%s" , msg) ;
-
-
ret = SendMsgTo ( sock_fd , msg , strlen( msg ) , ip_addr , port ) ;
-
-
if ( ret >= 0 )
-
{
-
printf ("client has sent %d bytes message to server\n" , ret) ;
-
goto success ;
-
}
-
-
else
-
goto error ;
-
-
error:
-
printf("main error") ;
-
goto success ;
-
success:
-
return 0 ;
-
}
4. server.cpp
-
// server.cpp
-
-
#include <stdio.h> // perror
-
#include <string.h> // memset
-
-
#include <sys/types.h> // AF_INET:IP , SOCK_STREMA:TCP , SOCK_DGRAM:UDP
-
#include <sys/socket.h> // socket , bind , sendto , recvfrom
-
#include <netinet/in.h> // sockaddr_in sockaddr , htons ,htonl , ntohs , ntohl
-
#include <arpa/inet.h> // inet_aton(2) , inet_ntoa(1)
-
#include <unistd.h> // unix standard library
-
-
#include "udpnet.h"
-
-
#define COMMON_PORT 1027
-
#define BUFFER_LEN 1024
-
#define IP_LEN 128
-
-
int main ( int c , char **v )
-
{
-
short port ;
-
char msg[BUFFER_LEN], ip_addr[IP_LEN] ;
-
int ret , sock_fd , msg_len ;
-
-
sock_fd = getSocketDone () ;
-
-
if ( sock_fd > 0 )
-
printf ("socket correct fd : %d \n", sock_fd) ;
-
else
-
goto error ;
-
-
if ( !getServerBindDone ( sock_fd) )
-
printf ("bind correct\n") ;
-
else
-
goto error ;
-
-
memset ( msg , 0 , sizeof(msg)) ;
-
memset ( ip_addr, 0 , sizeof(ip_addr) ) ;
-
msg_len = sizeof(msg) ;
-
-
printf ("server is watting for message from client\n ") ;
-
while ( ( ret = RecvMsgFrom ( sock_fd , msg , &msg_len ,
-
ip_addr , &port ) ) <0 ) ;
-
-
printf ("end waitting \n") ;
-
if ( msg_len )
-
{
-
printf ("server receive %d bytes from client \n" , msg_len ) ;
-
printf ( "message content [%s]\n" , msg ) ;
-
goto success ;
-
}
-
else
-
goto error ;
-
-
error:
-
printf ("main error") ;
-
goto success ;
-
success:
-
return 0 ;
-
}
运行程序
首先在 terminal 中启动 server 程序
./server
显示信息如下:
socket correct fd : 3
bind correct
server is watting for message from client
随后打开一个新的 terminal ,在该 terminal 中启动 client 程序
./client
显示信息如下
socket correct fd : 3
input message sent to server
根据提示信息,输入要发送到 server 的消息,回车结束
socket correct fd : 3
input message sent to server
hello_inuyasha (用户输入信息, 回车结束)
显示信息如下, client 工作结束
socket correct fd : 3
input message sent to server
hello_inuyasha
client has sent 14 bytes message to server
切回到 server 所运行的 terminal 中 ,发现显示的信息如下
socket correct fd : 3
bind correct
server is watting for message from client
end waitting
server receive 14 bytes from client
message content [hello_inuyasha]
阅读(1857) | 评论(0) | 转发(0) |