天天看點

簡單實作一種經典的資料傳輸模型

//内容描述:伺服器通過socket接收資料,他不停地監聽是否有用戶端來與其進行連接配接,如果有,就建立一個線程來處理用戶端發過來的資料,如果用戶端發送資料結束或者由于某種原因伺服器端接收資料失敗,則伺服器終止接收。

//在這裡簡單地實作一下,如果在工作當中要用到這種傳輸模型,則要比這個要考慮的嚴謹的多。如更健全的資料封裝,異常處理,資料池,發送失敗處理,接收失敗處理,資料儲存,甚至是還要加上生産者消費者模型。

//用戶端程式很簡單

// more Client.cpp

#include <iostream>

using namespace std;

#include <sys/types.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <netinet/in.h>

#include <cstdlib>

int main()

{

        int sd = socket(AF_INET, SOCK_STREAM, 0);

        if(sd == -1)cout << "client socket create error" << endl,exit(-1);

        struct sockaddr_in addr = {};

        addr.sin_family = AF_INET;

        addr.sin_port = htons(22222);

        addr.sin_addr.s_addr = inet_addr("127.0.0.1");

        int res = connect(sd, (struct sockaddr*)&addr, sizeof(addr));

        if(res == -1)cout << "connect failed" << endl,exit(-2);

        cout << "start send messages" << endl;

        char buf[222] = {};

        cin.getline(buf,222);

//發送資料,為了讓服務端能更容易看出多線程的效果,這裡讓同一條資訊連續發送15次,

//每次隔一秒,這樣就有可能一個人,用同一台機子,啟動多個用戶端,以便可以觀察到伺服器的動态,哎,這樣處理也是用心良苦啊~~

        int i =15;

        while(i--)

        {

                send(sd, buf, sizeof(buf), 0);

                sleep(1);

        }

        close(sd);

        return 0;

}

//伺服器端

#include <iostream>

using namespace std;

#include <cstdlib>

#include <sys/socket.h>

#include <sys/types.h>

#include <arpa/inet.h>

#include <netinet/in.h>

#include <cstring>

#include "thread_base.h"

class RecvData:public ThreadBaseClass

{

public:

        int csd;

        char buf[222];

public:

        RecvData()

        {

                csd = -1;

                memset(buf, 0, sizeof(buf));

        }

public:

        void run()

        {

                int res;

                while(1)

                {

                        res = recv(csd, buf, sizeof(buf), 0);

                        if(res > 0)

                                cout << buf << endl;

                        else

                        {

                                close(csd);

                                break;

                        }

                }

                cout << "delete this" << endl;

                delete this;//注意垃圾回收,雖然“delete this ”這種方式很不雅觀,但是它也可以達到及時回收記憶體的效果。

        }

};

int main()

{

        int sd = socket(AF_INET, SOCK_STREAM, 0);

        if(sd == -1)cout << "socket create error" << endl,exit(-1);

        struct sockaddr_in addr = {};

        addr.sin_family = AF_INET;

        addr.sin_port = htons(22222);

        addr.sin_addr.s_addr = inet_addr("127.0.0.1");

        int res = bind(sd, (struct sockaddr*)&addr, sizeof(addr));

        if(res == -1)cout << "bind error" << endl,exit(-2);

        cout << "bind success" << endl;

        if(-1 == listen(sd,10))cout << "listen error" << endl,exit(-3);

        struct sockaddr_in c_addr = {};

        socklen_t len = sizeof c_addr;

        while(1)

        {

                cout << "start accept" << endl;

                int csd = accept(sd, (struct sockaddr*)&c_addr, &len);

                cout << "accept success" << endl;

                RecvData *pRecvData = new RecvData();

                pRecvData->csd = csd;

                pRecvData->start();

        }

        return 0;

}