? ARM Linux环境下多连接TCP服务器的编程--技术天地

ARM Linux環境下多連接TCP服務器的編程

 2010/4/28    

        EM9160的主要功能之一就是作為網絡平臺,工控領域中比較常見的網絡應用是利用TCP/IP協議進行數據通訊。在網絡應用中,通常都實現多連接的應用需求,本文主要介紹EM9160作為TCP服務器方式的應用——支持多連接的TCP服務器示例程序:Step3_TCPServer。

 

TCP Socket編程

 

        在進行網絡應用程序開發方面大多是采用套接字Socket技術,嵌入式Linux的系統平臺上也是如此。Socket編程的基本函數有
socket( )、bind( )、listen( )、accept( )、send( )、sendto( )、recv( )、recvfrom( )、connect( )等。

 

支持多連接的TCP服務器應用示例

 

        Step3_TCPServe是一個支持多個客戶端的連接TCPServer示例,該例程采用了面向對象的C++編程,創建了CTCPServer和CTCPCustom兩個類,其中CTCPServer類負責偵聽客戶端的連接,一旦有客戶端請求連接,它就負責接受此連接,并創建一個新的CTCPCustom類對象與客戶端進行通訊,然后CTCPServer類接著監聽客戶端的連接請求,其流程如下:

 

Socket方式TCP服務器程序流程

 

        CTCPServer類

        CTCPServer類定義在TCPServer.h文件下,該類提供了3個公共函數,以及一個Socket偵聽線程,公共的函數中Open( )、Close( )用于啟動或是關閉TCP服務。

 

        class CTCPServer
        { 
        private:
                pthread_t m_thread; //通訊線程標識符ID
                //Socket偵聽線程

                static int SocketListenThread( void*lparam );
        public:
                int m_sockfd; //TCP服務監聽socket
                int m_ExitThreadFlag;
                int m_LocalPort; //設置服務端口號
                CTCPServer();
                virtual ~CTCPServer();
                int Open(); // 打開TCP服務
                int Close(); // 關閉TCP服務
                // 刪除一個客戶端對象連接 釋放資源
                int RemoveClientSocketObject( void* lparam );
        };

 

        在Open( )函數中實現了打開套接字,將套接字設置為偵聽套接字,并創建偵聽客戶端連接線程。在Linux應用程序中創建線程的方法在《嵌入式Linux串口通訊的C++設計》中有相關的說明,在該例程中也是采取的同樣方式。

 

        SocketListenThread函數中調用select( )偵聽客戶端的TCP連接,流程如下:

 

Socket方式TCP服務器程序流程

 

        同樣的需要注意的是,select( )函數中的時間參數在Linux下每次都需要重新賦值,否則會自動歸0。CTCPServer類的實現代碼請參見TCPServer.CPP文件。

 

        CTCPCustom類

        CTCPCustom的定義在TCPCustom.h文件下。

 

        class CTCPCustom
        {
        public:
                CTCPCustom();
                virtual ~CTCPCustom();
        public:
                char m_RemoteHost[100]; //遠程主機IP地址
                int m_RemotePort; //遠程主機端口號
                int m_socketfd; //通訊socket
                int m_SocketEnable;
                int m_ExitThreadFlag; 
                CTCPServer* m_pTCPServer;
        private
                // 通訊線程函數
                pthread_t m_thread; //通訊線程標識符ID
                static void* SocketDataThread(void* lparam); //TCP連接數據通訊線程
        public:
                int RecvLen;
                char RecvBuf[1500];
                // 打開socket,創建通訊線程
                int Open(void* lparam);
                // 關閉socket,關閉線程,釋放Socket資源
                int Close();
                // 向客戶端發送數據 
                int SendData(const char * buf , int len );
        };

 

        其中的SocketDataThread函數是實現TCP連接數據通訊的核心代碼,在該函數中調用select( )等待TCP連接的通訊數據,對于接收的TCP連接數據的處理也是在該函數中實現,在本例程中處理為簡單的數據回發,用戶可結合實際的應用修改此處代碼,流程如下:

 

Socket方式TCP服務器程序流程

 

        CTCPServer類的調用

        CTCPSerer類的具體使用也比較簡單,主要是調用對于類中定義Open函數來啟動各個TCP通訊線程,反而在主循環中需要實現的功能代碼不多了,在本例程中僅僅為每隔1s輸出提示信息。以下為Step3_TCPServer.cpp中的相關代碼。

 

        class CTCPServer m_TCPServer;
        int main()
        { 
                int i1;
                printf( 'Step3_TCPTest V1.0\n' );
                // 給TCP服務器端口賦值
                m_TCPServer.m_LocalPort = 1001;
                // 創建Socket,啟動TCP服務器偵聽線程
                i1 = m_TCPServer.Open( );
                if( i1<0 )
                {
                        printf( 'TCP Server start fail\n');
                        return -1; 
                }
                // 進入主循環,主要是負責管理工作
                for( i1=0; i1<10000;i1++) //實際應用時,可設置為無限循環
                {
                        sleep(1);
                        printf( '%d \n', i1+1);
                }
                m_TCPServer.Close( );
                return 0; 
        }