Chinaunix首页 | 论坛 | 博客
  • 博客访问: 562254
  • 博文数量: 97
  • 博客积分: 5090
  • 博客等级: 大校
  • 技术积分: 969
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-01 14:56
文章分类

全部博文(97)

文章存档

2011年(1)

2009年(1)

2008年(14)

2007年(37)

2006年(44)

我的朋友

分类: LINUX

2008-04-30 12:12:14

        Today, we learn how to develop a TCP Client-Server program, and that the Server is a daemon process as well as support multithreading.First, Let's look at the following technique points:
      Daemon processes
        Daemons are processes that live for a long time, and that they don't have a controlling termical, that is, they run in the background.A common use for a daemon process is as a server processes.A typical daemon process keep to the following coding steps:
        1. Call umask function to set the file mode creation mask to 0.
        2. Call fork function to create a child process and have the parent exit.
        3. Call setsid function to create a new session.
        4. Call chdir function to Change the current working directory to the root directory.
        5. To close the unneeded file descriptors.

      Network IPC:Sockets
        the socket network IPC interface can be used by processes to communicate with other processes, regardless of where they are running on the same machine or on different machines.In general, a server is a process that waits for a client to connect it, requesting some type of service.that is, the client sends a request to the server, and the server sends a reply back to the client.A typical TCP Server process keep the following coding steps:
        1. Call socket function to create a socket descriptor.
        2. Call bind function to associate an address with a socket descriptor.
        3. Call listen function to announce that the server is willing to accept connect request.
        4. Call accept function to retrieve a connect request and convert that into a connection.
        5. Call recv function to receive data from a client.
        6. Call send function to send data to a client .
        7. Go to step 4.

        A typical TCP client keep the following coding steps:
        1. Call socket function to create a socket descriptor.
        2. Call connect function to connect to a server.
        3. Call send function to send data to a server.
        4. Call recv function to receive data from a server.

      Multithreading
        A typical process can be thought of as having a single thread of control:each process is doing only one thing at a time.With multiple threads of control, we can design our programs to do more than one thing at a time within a single process, with each thread handling a separate task.

    For detail information, please see the following source code:


//*****************************************************************************************
// File Name:TCPClient.cpp
// By Jiafeng Luo
// Description:this file contains main function which sends data to a server and get reply
// Date : April 29, 2008
// Copyright:
//*****************************************************************************************

文件:TCPClientServer.rar
大小:48KB
下载:下载



#include <iostream>
using namespace std;
#include "../WLSocket.h"

int main(int argc, char* argv[])
{
    CWLSocket clientsock;
    clientsock.Connect("127.0.0.1", 5000);
    cout << "Please type what you want to say:" << endl;
    char szBuf[1024] = "jiafengjinghua";
    cin.getline(szBuf, sizeof(szBuf));
    clientsock.Send(szBuf, sizeof(szBuf));
    clientsock.Recv(szBuf, sizeof(szBuf));
    cout << szBuf << endl;
#ifdef WIN32
    system("pause");
#endif
    return 0;
}

//*******************************************************************************************
// File Name:TCPServer.cpp
// By Jiafeng Luo
// Description:this file contains main function which listening for an incoming connection
// Date : April 29, 2008
// Copyright:
//*******************************************************************************************

#include "../WLSocket.h"
#include "./WLThread.h"
#include "../Global.h"

#ifndef WIN32
void Daemonize()
{
    int                 fd0, fd1, fd2;
    pid_t               pid;
    struct rlimit       rl;
    struct sigaction    sa;
    // step 1:Clear file creation mask
    umask(0);
    //Get maximum number of file descriptors
    getrlimit(RLIMIT_NOFILE, &rl);
    // step 2:Become a session leader to lose controlling TTY
    if ( (pid = fork()) < 0 )  // fork error
        exit(-1);
    else if ( pid != 0 )      // have parent exit
        exit(0);
    setsid();                // child become a session leader to lose controlling TTY
    //Ensure future opens won't allocate controlling TTYs.
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if ( sigaction(SIGHUP, &sa, NULL) < 0 )
        exit(-1);
    if ( ( pid = fork() ) < 0 )   // fork error
        exit(-1);
    else if ( pid != 0 )         // have parent exit
        exit(0);
    // step 3:Change the current working directory to the root
    chdir("/");
    // step 4:Close all open file descriptors
    if ( rl.rlim_max == RLIM_INFINITY )
        rl.rlim_max = 1024;
    for ( int i = 0; i < rl.rlim_max; i++ )
        close(i);
    // Attache file descriptors 0, 1, and 2 to /dev/null
    fd0 = open("/dev/null", O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);
}
#endif

int main(int argc, char* argv[])
{
#ifndef WIN32
    Daemonize();
#endif
    CWLSocket socket;
    socket.Listen("127.0.0.1", 5000, 8);
    sockaddr addr;
    int nLen = sizeof(struct sockaddr);
    while ( true )
    {
        SOCKET sock = socket.Accept(&addr, &nLen);
        CWLThread doservice;
        THREADHANDLE it = doservice.CreateWLThread((void*)sock);
        doservice.WaitThread();
    }
    return 0;
}

//************************************************************************************************************
// File Name:WLSocket.h
// By Jiafeng Luo
// Description:this class disign to communicate by socket between network processes on both Linux and Windows
// Date : April 29, 2008
// Copyright:
//************************************************************************************************************

#ifndef WLSOCKET_H__
#define WLSOCKET_H__

#include "./Global.h"
class CWLSocket
{
public:
    CWLSocket(void);
    CWLSocket(SOCKET clientSocket);                           // constructor
    ~CWLSocket(void);                                         // deconstructor
    int Connect(const char* szAddr, int nPort, int nReconnectTimes = 1);// the Connect function establishs a connection to a specified socket
    int Listen(const char* szAddr, int nPort, int backlog);// the Listen function listing for an incoming connection
    SOCKET Accept(struct sockaddr* addr, int* addrlen);    // the Accept function permits an incoming connection attempt on a socket
    int Send(const char* szBuf, int nLen, int flags = 0);  // the Send function sends data on a connected socket(data member m_socket)
    int Recv(char* szBuf, int nLen, int flags = 0);        // the Recv function receives data from a connect socket(data member m_socket)
private:
    SOCKET Socket( int af = AF_INET, int type = SOCK_STREAM, int protocol = 0);// the Socket function creates a socket that is bound to a specific service provider

    int Bind(const char* szAddr, int nPort);// the Bind function associates a local address with a socket(data member m_socket)
private:
    SOCKET m_socket;                                                           // socket descriptor
};
#endif

//************************************************************************************************************
// Filename:WLSocket.cpp
// By Luo Jiafeng
// Description:this class disign to communicate by socket between network processes on both Linux and Windows
// Date:April 29,2008
// Copyright:
//************************************************************************************************************

#include "WLSocket.h"

//
************************************************************************
// Function:CWLSocket
// Description:Which is default constructor funcation
// Return values:None
//
************************************************************************
CWLSocket::CWLSocket(void) : m_socket(INVALID_SOCKET)
{
#ifdef WIN32
    WSAData wsaData;
    WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
#endif
}

//************************************************************************
// Function:CWLSocket
// Description:Which is over loading constructor funcation
// Return values:None
//************************************************************************
CWLSocket::CWLSocket(SOCKET clientSocket) : m_socket(clientSocket)
{
}

//*
************************************************************************
// Function:~CWLSocket
// Description:Which is Deconstructor funcation
// Return values:None
//*************************************************************************
CWLSocket::~CWLSocket(void)
{
#ifdef WIN32
    closesocket(m_socket);
    m_socket = INVALID_SOCKET;
#else
    close(m_socket);
    m_socket = INVALID_SOCKET;
#endif
}

//*************************************************************************
// Function:Socket
// Description:To create a socket
// Parameters:
// af:[in] Address family specification
// type: [in] Type for specification the new socket
// protocol: [in] Protocol to be used with the socket that is specific to the indicated address family
// Return values:socket descriptor if OK, -1 on error
//**************************************************************************
SOCKET CWLSocket::Socket( int af /* = AF_INET */, int type /* = SOCK_STREAM */, int protocol /* = 0 */ )
{
    m_socket = socket(af, type, protocol);
    return m_socket;
}

//**************************************************************************
// Function:Bind
// Description:the function associates a local address with a socket
// Parameters:
// szAddr: [in]Null-terminated character string representing a number expressed in the Internet standard "."(dotted) notation
// nPort: [in] IP port
// Return values:Zero if OK, -1 on error
//**************************************************************************
int CWLSocket::Bind(const char* szAddr, int nPort)
{
#ifdef WIN32
    assert( m_socket != INVALID_SOCKET );
#else
    assert( m_socket != INVALID_SOCKET );
#endif
    sockaddr_in socketaddr;
    memset(&socketaddr, '\0', sizeof(sockaddr_in));
    socketaddr.sin_family = AF_INET;
    socketaddr.sin_port = nPort;
    socketaddr.sin_addr.s_addr = inet_addr(szAddr);
    return bind(m_socket, (struct sockaddr *)&socketaddr, sizeof(struct sockaddr));
}

//**************************************************************************
// Function:Connect
// Description:the Function connect to a server
// Parameters:
// szAddr:[in]Null-terminated character string representing a number expressed in the Internet standard "."(dotted) notation
// nPort:[in]IP port
// nReconnectTimes:the times of reconnect
// Returns:zero if OK, otherwise, the value SOCKET_ERROR is returned
//**************************************************************************
int CWLSocket::Connect(const char* szAddr, int nPort, int nReconnectTimes /* = 1 */)
{
    Socket(AF_INET, SOCK_STREAM, 0);
    assert( m_socket != INVALID_SOCKET );
    int nReturn = SOCKET_ERROR;
    int nConnectTimes = 0;
    sockaddr_in socketaddr;
    memset(&socketaddr, '\0', sizeof(sockaddr_in));
    socketaddr.sin_family = AF_INET;
    socketaddr.sin_port = nPort;
    socketaddr.sin_addr.s_addr = inet_addr(szAddr);
    while (nConnectTimes < nReconnectTimes && SOCKET_ERROR == nReturn)
    {
        nReturn = connect(m_socket, (struct sockaddr *)&socketaddr, sizeof(struct sockaddr));
        if (nReturn != SOCKET_ERROR)
        {
            return nReturn;
        }
        else
            nConnectTimes++;
    }
    return SOCKET_ERROR;
}

//*
**************************************************************************
// Function: Listen
// Description:the function places data member m_socket a state where it is listening for an incoming connection.
// Parameters:
// szAddr:[in] Null-terminated character string representing a number expressed in the Internet standard "."(dotted) notation
// nPort:[in] IP port
// backlog:[in] Maximum length of the queue of pending connections
// Return values:If no error occurs, Listen returns zero. Otherwise, a value of SOCKET_ERROR is returned
//
***************************************************************************
int CWLSocket::Listen(const char* szAddr, int nPort, int backlog)
{
    Socket(AF_INET, SOCK_STREAM, 0);
    Bind(szAddr, nPort);
    return listen(m_socket, backlog);
}

//
****************************************************************************
// Funcation:Accept
// Description:the funcation permits an incomming connection attempt on a socket(the data member "m_socket" )
// Parameters:
// addr:[out]Optional pointer to a buffer that receives the address of the connection entity
// addrlen:[out]Optional pointer to an integer that contains the length of the parameter addr
// Return values: If no error occurs, the function returns a value of type SOCKET that is a descriptor for the new socket.
// Otherwise, a value of INVALID_SOCKET is returned.
//****************************************************************************
SOCKET CWLSocket::Accept(struct sockaddr* addr, int* addrlen)
{
#ifdef WIN32
    return accept(m_socket, addr, addrlen);
#else
    return accept(m_socket, addr, (socklen_t *)addrlen);
#endif
}

//*
****************************************************************************
// Function: Send
// Description:the funcation sends data on a connected socket(the data member m_socket)
// Parameters:
// szBuf:[in] Buffer contained the data to be transmitted
// nLen:[in] Lengh of the data in szBuf
// flags:[in] Indicator specifying the way in which the call is made
// Return values: If no error occurs, send returns the total number of bytes sent, which can be less than the number indicated by len.
// Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling
//*****************************************************************************
int CWLSocket::Send(const char* szBuf, int nLen, int flags/* = 0*/)
{
    int nSendLen = 0;
    while (nSendLen < nLen)
    {
        int nCount = send(m_socket, szBuf + nSendLen, nLen - nSendLen, flags);
        if (nCount <= 0)
        {
            return SOCKET_ERROR;
        }
        else
        {
            nSendLen += nCount;
        }
    }
    return nSendLen;
}

//*
*****************************************************************************
// Function: Recv
// Description:the function receive data from a client or a server
// Parameters:
// szBuf:[out] Buffer for the incoming data
// nLen:[in] Lengh of the szBuf
// flags:[in] Flag specifying the way in which the call is made
// Return values:If no error occurs, recv returns the number of bytes received. If the connection has been gracefully closed,
// the return value is zero. Otherwise, a value of SOCKET_ERROR is returned
//******************************************************************************
int CWLSocket::Recv(char* szBuf, int nLen, int flags/* = 0*/ )
{
    int nRecvLen = 0;
    while (nRecvLen < nLen)
    {
        char *pszBuf = new char[nLen];
        memset(pszBuf, '\0', nLen);
        int nCount = recv(m_socket, pszBuf + nRecvLen, nLen - nRecvLen, flags);
        if (nCount <= 0)
        {
            delete pszBuf;
            pszBuf = NULL;
            return SOCKET_ERROR;
        }
        else
        {
            memcpy(szBuf + nRecvLen, pszBuf, nCount);//可能有问题

            nRecvLen += nCount;
            delete pszBuf;
            pszBuf = NULL;
        }
    }
    return nRecvLen;
}

//*************************************************************************************************************
// File Name:WLThread.h
// By Jiafeng Luo
// Description:this class disign to create thread on both Linux and Windows
// Date : April 29, 2008
// Copyright:
//*************************************************************************************************************
#ifndef WLTHREAD_H__
#define WLTHREAD_H__

#include "../Global.h"
class CWLThread
{
public:
    CWLThread(void);                                       //constructor
    ~CWLThread(void);                                      //deconstructor
    //The CreateWLThread funcation creates a thread to execute within the virtual address space of the calling process
    THREADHANDLE CreateWLThread(THREAD_START_ROUTINE lpStartAddress, void *lpParameter);   
    //The CreateWLThread funcation creates a thread to execute within the virtual address space of the calling process
    THREADHANDLE CreateWLThread(void *lpParameter);                                            
    int WaitThread();                //The WaitThread funcation waits for the thread exit
private:
    static THREAD_RETURN_TYPE ThreadProc(void* lpParameter);//The ThreadProc funcation serves as the starting address for a thread specify this address when calling the CreateWLThread Function.


private:
    THREADHANDLE m_threadhandle;                           //thread descriptor

};
#endif

//**************************************************************************
// File Name:WLThread.cpp
// By Jiafeng Luo
// Description:this class disign to create thread on both Linux and Windows
// Date : April 29, 2008
// Copyright:
*****************************************************************************

#include "WLThread.h"
#include "../Global.h"
#include "../WLSocket.h"

CWLThread::CWLThread(void) : m_threadhandle(0) {}
CWLThread::~CWLThread(void) {}

//******************************************************************************
// Function:CreateWLThread
// Description:The CreateWLThread funcation creates a thread to execute within the virtual address space of the calling process
// Parameters:
// lpStartAddress:[in] Pointer to the application-defined function of type THREAD_START_ROUTINE
                       to be executed by the thread and represents the starting address of the thread.
// lpParameter: [in] Specifies a single parameter value passed to the thread
// Return values:If the function succeeds, the return value is a handle to the new thread, otherwise the return value is NULL
//******************************************************************************
THREADHANDLE CWLThread::CreateWLThread(THREAD_START_ROUTINE lpStartAddress, void *lpParameter)
{
#ifdef WIN32
    DWORD dwThreadID = 0;
    m_threadhandle = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)lpStartAddress, lpParameter, 0, &dwThreadID);
#else
    pthread_create(&m_threadhandle, NULL, (THREAD_START_ROUTINE)lpStartAddress, lpParameter);
#endif
    return m_threadhandle;
}


//*
******************************************************************************
// Function:CreateWLThread
// Description:The CreateWLThread funcation creates a thread to execute within the virtual address space of the calling process
             The static member function ThreadProc to be executed by thre thread and represents the starting address of the thread
// Parameters:
// lpParameter: [in] Specifies a single parameter value passed to the thread
// Return values:If the function succeeds, the return value is a handle to the new thread, otherwise the return value is NULL
// *******************************************************************************
THREADHANDLE CWLThread::CreateWLThread(void *lpParameter)
{
#ifdef WIN32
    DWORD dwThreadID = 0;
    m_threadhandle = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)CWLThread::ThreadProc, lpParameter, 0, &dwThreadID);
#else
    pthread_create(&m_threadhandle, NULL, (THREAD_START_ROUTINE)CWLThread::ThreadProc, lpParameter);
#endif
    return m_threadhandle;
}

//*
*******************************************************************************
// Function:ThreadProc
// Description:The ThreadProc funcation serves as the starting address for a thread specify this address when calling the CreateWLThread Function.
// Parameters:
// lpParameter: [in] Receives the thread data passed to the function using the lpParameter parameter of the CreateWLThread function
// Return values:the function should return a value that indicates its success or failure
//********************************************************************************
THREAD_RETURN_TYPE CWLThread::ThreadProc(void *lpParameter)
{
    CWLSocket clientsock((SOCKET)lpParameter);
    char szBuf[1024];
    clientsock.Recv(szBuf, sizeof(szBuf));
    strcat(szBuf, "--Message from server");
    clientsock.Send(szBuf, sizeof(szBuf));
    return (THREAD_RETURN_TYPE)0;
}

//*
********************************************************************************
// Function:WaitThread
// Description:The WaitThread funcation waits for the thread exit
// Parameters:None
// Return values:the function return a value thread exit status
//
*********************************************************************************
int CWLThread::WaitThread()
{
#ifdef WIN32
    return WaitForSingleObject(m_threadhandle, INFINITE);
#else
    return pthread_join(m_threadhandle, NULL);
#endif
}

#ifndef GLOBAL_H__
#define GLOBAL_H__

#ifdef WIN32
    #include <windows.h>
    #include <WinSock.h>
    #include <tchar.h>
    #pragma comment(lib, "WSock32.lib")
    typedef DWORD THREAD_RETURN_TYPE;
    typedef THREAD_RETURN_TYPE (*THREAD_START_ROUTINE)(LPVOID);
    typedef HANDLE    THREADHANDLE;
#else
    #include <sys/socket.h>
    #include <sys/resource.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <errno.h>
    typedef void* THREAD_RETURN_TYPE;
    typedef THREAD_RETURN_TYPE (*THREAD_START_ROUTINE)(void*);
    typedef int                    SOCKET;
    typedef pthread_t            THREADHANDLE;
    #define SOCKET_ERROR                (-1)
    #define INVALID_SOCKET            (-1)
#endif
#include <assert.h>
#include <iostream>
using namespace std;

#endif

阅读(1549) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~