全部博文(298)
分类: LINUX
2011-04-05 15:10:32
(11)创建实用套接字类库
注:所以文章红色字体代表需要特别注意和有问题还未解决的地方,蓝色字体表示需要注意的地方
1. 本文所介绍的程序平台
开发板:arm9-mini2440
虚拟机为:Red Hat Enterprise Linux 5
开发板上系统内核版本:linux-2.6.32.2
2. 创建静态链接库
2.1 创建库文件
静态链接库包括一些编译后的文件,他们在链接时连接到程序中,而与运行无关,所以在运行的时候不需要相应的库文件。
gcc -c object1.c 提供编译文件
在unix中系统提供ar命令可用于创建静态链接库,例如:
ar rc libmyutil.a object1.o object2.o object3.o
此命令创建一个名为libmyutil.a的库文件,其中包括object1.o object2.o object3.o三个已编译的文件,如果库文件已创建则将3个文件加入到库文件里面,如果有重复的就替换。
2.2 建立库文件索引
创建库文件后,需要创建库文件索引才能被编译器所用。
ranlib libmyutil.a
注意:由于经过测试ranlib 建立索引之后并不能引用,不知道为什么,连索引文件都没,但是可以将libmyutil.a文件拷贝到用户静态库文件夹,用法还是一样的,我电脑上的用户静态库文件夹为/usr/lib
此命令为库文件libmyutil.a建立索引
2.3 连接库文件
在连接时只需要用-l参数,将库文件连接到可执行文件中,例如:
gcc main.c –lmyutil –o programname
此命令将目标文件(main.o)、库文件(libmyutil.a)连接到可执行文件programname,使用-l参数时,前缀lib与后缀.a都由编译器自动加上。
3.创建动态链接库
动态链接库又称共享库,在连接时,链接器只是检查程序所需要的符号,并不将代码连接到可执行文件中。只有在程序运行的时,由系统将相应的库导入到内存中,并将所需代码与程序代码想连接,这样多个可执行程序可共享相同的库,从而有效地节省内存空间。
3.1创建库文件
为了创建动态链接库,首先要产生与位置无关的代码,例如;
gcc -fPIC -c object1.c
此命令产生与位置无关代码的目标文件object1.o
然后再创建库文件,例如:
gcc -shared libmyutil.so object1.o object2.o object3.o
此命令创建动态链接库库名为libmyutil.so,其中-shared表示创建动态链接库,object1.o object2.o object3.o是库文件中包含的目标文件。
3.2 使用动态链接库
包括两个步骤:
(1) 编译时,链接器检查所需要的动态链接库,确保其包括生成的可执行文件所需的所有符号,这时不将代码插入到执行文件中;
(2) 在程序运行时候需要告诉系统的动态加载程序动态链接库的位置,编译时与静态链接库相同,例如;
gcc main.c –lmyutil –o programname
此命令将目标文件(main.o)、库文件(libmyutil.so)连接到可执行文件programname,使用-l参数时,前缀lib与后缀.a都由编译器自动加上,链接器自动查找动态链接库。
在运行系统动态加载程序将在指定的系统目录下查找相应的动态链接库,例如:/lib,/usr/lib,/usr/X11/lib等,如果创建的动态链接库不在系统目录下,则必须设置LD_LIBRARY_PATH环境变量,可以用ldd命令来检查系统时候能正确地找到程序所加载的动态链接库。
注意:在进行链接的时候注意顺序。
3.2.1 相互引用的库文件
如果库文件A和库文件B相互引用对方的符号,则一个库文件需要引用两次,例如:
gcc main.o –lA –lB –lA
当然这种引用方法效率很低。
3.2.2动态库文件和静态库文件共存
如果系统中同时存在动态库文件和静态库文件,链接器首先检查动态库文件
4. 创建自定义的套接字类库
我们将第一次必须将C语言的形式的系统调用封装到相应的类中,即Wrapper类,在此类基础上建立一些共用类和应用类。
4.1 Wrapper类
MyScoket类:封装基础的套接字系统调用,并且实现异常处理,为了满足不同的需求提供了不同的函数调用。
MyThread 类:封装了POSIX线程的系统调用以实现多线程,并且提供了简单明了的方法来产生线程。
MyMutux类:提供了实现互斥锁的基本方法。
MyCondition类:提供实现条件变量的基本方法。
4.2 共用类
TcpServThr类:提供实现基于TCP多线程服务器的方法。
TcpCliThr类:提供实现基于TCP多线程客户的方法。
MessageQue类:提供实现带互斥锁的队列的方法。
4.3 应用类
ChatServer类:一个简单的聊天室服务器类,是一个TCP多线程并发服务器的方法。
CharClient类:一个简单的聊天室客户类,是一个TCP多线程客户的方法。
虚函数:
虚函数必须是基类的非函数,其访问权限可以是protected或public,在基类的类定义中定义虚函数的一般形式:
virtual 函数返回值类型 虚函数名(形参表)
{ 函数体 }
虚函数的作用是实现,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。
当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。
虚函数的实例 #include
class Cshape
{ public: void SetColor( int color) { m_nColor=color;}
void virtual Display( void) { cout<<"Cshape"<
private:
int m_nColor;
};
class Crectangle: public Cshape
{
public:
void virtual Display( void) { cout<<"Crectangle"<
};
class Ctriangle: public Cshape
{
void virtual Display( void) { cout<<"Ctriangle"<
};
class Cellipse :public Cshape
{
public: void virtual Display(void) { cout<<"Cellipse"<
};
void main()
{
Cshape obShape;
Cellipse obEllipse;
Ctriangle obTriangle;
Crectangle obRectangle;
Cshape * pShape[4]=
{ &obShape, &obEllipse,&obTriangle, & obRectangle };
for( int I= 0; I< 4; I++)
pShape[I]->Display( );
}
本程序运行结果:
Cshape
Cellipse
Ctriangle
Crectangle
MyScoket类:
/****************************************************
class name : MySocket
Function: A wrapper class of basic socket function.
******************************************************/
class MySocket
{
protected: // Socket variables
sa_family_t address_family; //存放地址簇 如:AF_INEF
int protocol_family; // 存放协议簇如:IPPROTO_TCP
int socket_type; //套接字类型如:SOCK_STREAM SOCK_DGRAM
int port_number; //端口号
int Mysocket; // 套接字描述符
int conn_socket; // 连接套接字描述符
MySocketError socket_error; // 自定义套接字错误码
protected: // Process control variables
int bytes_read; // 读入字节数
int bytes_moved; // 写出的字节数
int is_connected; // 是否已经连接 0表示未连接
int is_bound; // 套接字是否已经绑定
public: // Data structures used to set the internet domain and addresses
sockaddr_in sin; // 本地套接字地址
sockaddr_in remote_sin; // 远程套接字地址
public: //构造函数和析构函数
MySocket();
MySocket(int st, int port, char *hostname = 0);
MySocket(sa_family_t af, int st, int pf,
int port, char *hostname = 0);
virtual ~MySocket();
public: // 参数设置
void SetAddressFamily(sa_family_t af) { address_family = af; }
void SetProtocolFamily(int pf) { protocol_family = pf; }
int GetProtocolFamily() { return protocol_family; }
void SetSocketType(int st) { socket_type = st; }
int GetSocketType() { return socket_type; }
void SetPortNumber(int p) { port_number = p; }
int GetBoundSocket() { return Mysocket; }
int GetSocket() { return Mysocket; }
int GetRemoteSocket() { return conn_socket; }
public: //套接字功能函数 用于套接字初始化连接等
int Socket();
int InitSocket(int st, int port, char *hostname = 0);
int InitSocket(sa_family_t af, int st,
int pf, int port, char *hostname = 0);
void Close();
void Close(int &s);
void CloseSocket();
void CloseRemoteSocket();
int Bind();
int Connect();
int Accept();
int Listen(int max_connections = MAXCONN);
//基于流的I/O功能 用于TCP的读写操作
//函数重载实现不同的功能
int Recv(void *buf, int bytes, int flags = 0);
//just for client
int Recv(int s, void *buf, int bytes, int flags = 0);
int Recv(void *buf, int bytes, int seconds, int useconds, int flags = 0);
//just for client
int Recv(int s, void *buf, int bytes, int seconds, int useconds,
int flags = 0);
int Send(const void *buf, int bytes, int flags = 0);
//just for client
int Send(int s, const void *buf, int bytes, int flags = 0);
int RemoteRecv(void *buf, int bytes, int seconds, int useconds,
int flags = 0);
//just for server
int RemoteRecv(void *buf, int bytes, int flags = 0);
//just for server
int RemoteSend(const void *buf, int bytes, int flags = 0);
//just for server
void ResetRead() { bytes_read = 0; }
void ResetWrite() { bytes_moved = 0; }
void ShutDown(int how = 0);
void ShutDown(int &s, int how = 0);
void ShutDownSocket(int how = 0);
void ShutDownRemoteSocket(int how = 0);
//套接字信息数据库功能 用于获取与套接字相关的参数
int GetPeerName(int s, sockaddr_in *sa);
int GetPeerName();
int GetSockName(int s, sockaddr_in *sa);
int GetSockName();
int GetSockOpt(int s, int level, int optName,
void *optVal, unsigned *optLen);
int GetSockOpt(int level, int optName, void *optVal, unsigned *optLen);
int SetSockOpt(int s, int level, int optName,
const void *optVal, unsigned optLen);
int SetSockOpt(int level, int optName, const void *optVal, unsigned optLen);
int GetServByName(char *name, char *protocol = 0);
int GetServByPort(int port, char *protocol = 0);
servent *GetServiceInformation(char *name, char *protocol = 0);
servent *GetServiceInformation(int port, char *protocol = 0);
int GetPortNumber();
int GetRemotePortNumber();
int GetHostName(char *sbuf);
int GetIPAddress(char *sbuf);
int GetDomainName(char *sbuf);
int GetBoundIPAddress(char *sbuf);
int GetRemoteHostName(char *sbuf);
hostent *GetHostInformation(char *hostname);
void GetClientInfo(char *client_name, int &r_port);
sa_family_t GetAddressFamily();
sa_family_t GetRemoteAddressFamily();
// 套接字状态功能
int ReadSelect(int s, int seconds, int useconds);
int BytesRead() { return bytes_read; }
int BytesMoved() { return bytes_moved; }
int SetBytesRead(int bytes = 0) { return bytes_read = bytes; }
int SetBytesMoved(int bytes = 0) { return bytes_moved = bytes; }
int *GetBytesRead() { return &bytes_read; }
int *GetBytesMoved() { return &bytes_moved; }
int IsConnected() { return is_connected == 1; }
int IsBound() { return is_bound == 1; }
int SetSocket(int s) { return Mysocket = s; }
int SetRemoteSocket(int s) { return conn_socket = s; }
void ReleaseSocket() { Mysocket = (int)-1; }
void ReleaseRemoteSocket() { conn_socket = (int)-1; }
// 基于数据包I/O功能 用于UDP的读写操作
int RecvFrom(int s, sockaddr_in *sa, void *buf,
int bytes, int seconds, int useconds, int flags = 0);
int RecvFrom(int s, sockaddr_in *sa, void *buf,
int bytes, int flags = 0);
int SendTo(int s, sockaddr_in *sa, void *buf,
int bytes, int flags = 0);
int RecvFrom(void *buf, int bytes, int flags = 0);
int RecvFrom(void *buf, int bytes, int seconds, int useconds, int flags = 0);
int SendTo(void *buf, int bytes, int flags = 0);
//异常处理功能
MySocketError GetSocketError() { return socket_error; }
MySocketError GetSocketError() const { return socket_error; }
MySocketError SetSocketError(MySocketError err) {
return socket_error = err;
}
MySocketError ResetSocketError() {
return socket_error = MySOCKET_NO_ERROR;
}
MySocketError ResetError() {
return socket_error = MySOCKET_NO_ERROR;
}
};
MyThread 类:
/*************************************************
class name : Thread_interface
function: It is base class of all threads. used by class Mythread.
****************************************************/
class Thread_interface
{
public:
virtual void run(){} //仅包含虚函数
};
/*******************************************************
class name : MyThread
function: Create thread and run it.
***************************************************************/
class MyThread : public Thread_interface//继承基类Thread_interface
{
Thread_interface* worker;
//定义指向Thread_interface的指针,所指的对象是线程将要执行的实体
int error;
pthread_t id;//存放线程ID
static void* run(void*); //声明静态的函数run(),用于产生线程
public:
MyThread(Thread_interface& w);
MyThread() {worker = this;}
int Start();
void Exit(void *value_ptr) { ::pthread_exit(value_ptr);}
int Join(pthread_t thread, void **value_ptr) { error = ::pthread_join(thread, value_ptr); return error;}
int Cancel(pthread_t target_thread){ error = ::pthread_cancel(target_thread); return error;}
int Detach() {error = ::pthread_detach(id); return error;}
int Detach(pthread_t thread) {error = ::pthread_detach(thread); return error;}
pthread_t getId() {return id;}
int Error(){return error;}
};
MyMutux类:
/****************************************************
class name : MyMutex
Function: support mutex
******************************************************/
class MyMutex
{
pthread_mutex_t a_mutex;
int error;
public:
MyMutex();
~MyMutex();
int Lock() { error = pthread_mutex_lock(&a_mutex);return error;}
int Trylock() { error = pthread_mutex_trylock(&a_mutex); return error;}
int Unlock() {error = pthread_mutex_unlock(&a_mutex); return error;}
int Error() {return error;}
};
/****************************************************
class name : MyCondition
Function: support MyCondition variable
******************************************************/
class MyCondition
{
pthread_mutex_t a_mutex;
pthread_cond_t got_request;
int error;
public:
MyCondition();
~MyCondition();
int wait(int second = 0); // wait until signal by other thread
int wake(); // wake a thread waiting for this condition
int wakeAll(); // wake all threads waiting for this conditoin
int Error() {return error;}
};
TcpServThr类:
完成功能:
(1) TCP套接字的创建、绑定,并且负责建立/关闭连接套接字,以及套接字读写操作,TcpServThr类通过继承MySocket类来实现。
(2) 并发功能。TcpServThr类通过定义两个内部类Receiver和Sender来产生线程,分别完成发送和接收功能,并且建立一个线程队列来完成线程的管理。
/****************************************************
class name : TcpServThr
Function: support TCP Server with multithread
******************************************************/
class TcpServThr : public MySocket
{
int max_connections;//存放最大连接数
vector
//ThrSet指向的是一个线程队列的指针,该队列存放当前所有线程??
public:
TcpServThr();
TcpServThr(int port, char *hostname = NULL);
TcpServThr(int port, int maxconn, char *hostname = NULL);
virtual ~TcpServThr();
void SetMaxConn(int num) {max_connections = num;}//设置最大连接数
int GetMaxConn() {return max_connections;}//获取最大连接数
int Init();
int Run(); //用于运行TCP,建立连接
virtual void DealRecv(MyThread* thread);
virtual void DealSend(MyThread* thread);
protected:
int CreateThr(MyThread** Rthread, MyThread** Wthread);//用于产生收发线程
void AddThread(MyThread* thread);//将线程加入队列
void DelThread(MyThread* thread);//将线程从队列中删除
int WaitAllThr();//用于线程退出时的同步
// Receiver类 用于产生接收线程
class Receiver : public MyThread
{
public:
int socket;
TcpServThr* server;
Receiver(int connsocket, TcpServThr* serv) {
socket = connsocket;
server = serv;
}
void run() { server->DealRecv(this); }
};
// Sender类 用于产生发送线程
class Sender : public MyThread
{
public:
int socket;
TcpServThr* server;
Sender(int connsocket, TcpServThr* serv) {
socket = connsocket;
server = serv;
}
void run() { server->DealSend(this); }
};
};
TcpCliThr类:
功能:
(1)TCP套接字的创建、关闭以及与服务器的连接以及读写操作,它通过继承MySocket类来实现
(2)并发功能,与TcpServThr完全相同
/****************************************************
class name : TcpCliThr
Function: support TCP Server with multithread
******************************************************/
class TcpCliThr : public MySocket
{
vector
//ThrSet指向的是一个线程队列的指针,该队列存放当前所有线程??
public:
TcpCliThr ();
TcpCliThr (int port, char *server);
virtual ~TcpServThr();
int ConnectServ();//用于与服务器连接
virtual void DealRecv(MyThread* thread);
virtual void DealSend(MyThread* thread);
protected:
int CreateThr(MyThread** Rthread, MyThread** Wthread);//用于产生收发线程
void AddThread(MyThread* thread);//将线程加入队列
void DelThread(MyThread* thread);//将线程从队列中删除
int WaitAllThr();//用于线程退出时的同步
// Receiver类 用于产生接收线程
class Receiver : public MyThread
{
public:
int socket;
TcpCliThr * server;
Receiver(int connsocket, TcpCliThr * serv) {
socket = connsocket;
server = serv;
}
void run() { server->DealRecv(this); }
};
// Sender类 用于产生发送线程
class Sender : public MyThread
{
public:
int socket;
TcpCliThr * server;
Sender(int connsocket, TcpCliThr * serv) {
socket = connsocket;
server = serv;
}
void run() { server->DealSend(this); }
};
};