簡體   English   中英

C ++多客戶端TCP服務器

[英]C++ Multi-Client TCP Server

我想使用C ++使用TCP協議制作服務器和客戶端程序。 該服務器必須能夠一次處理多個客戶端。 但是問題是,例如,啟動服務器后,我使用服務器的IP地址和端口作為參數運行2個客戶端。 接下來,兩個客戶端都將數據發送到服務器。 首先,兩個客戶端都可以將數據發送到服務器,並且服務器能夠讀取數據。 但是,一旦服務器已從第二個客戶端接收到數據,則它似乎已停止從第一個客戶端接收到數據。 你有什么解決辦法嗎?

這是服務器代碼

using namespace std;

void *task1(void *);

static int connFd;
void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char* argv[])
{
    int pId, portNo, listenFd;
    socklen_t len; //store size of the address
    bool loop = false;
struct sockaddr_in svrAdd, clntAdd;

pthread_t threadA[3];

if (argc < 2)
{
    cerr << "Syntam : ./server <port>" << endl;
    return 0;
}

portNo = atoi(argv[1]);

if((portNo > 65535) || (portNo < 2000))
{
    cerr << "Please enter a port number between 2000 - 65535" << endl;
    return 0;
}

//create socket
listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if(listenFd < 0)
{
    cerr << "Cannot open socket" << endl;
    return 0;
}

bzero((char*) &svrAdd, sizeof(svrAdd));

svrAdd.sin_family = AF_INET;
svrAdd.sin_addr.s_addr = INADDR_ANY;
svrAdd.sin_port = htons(portNo);

//bind socket
if(bind(listenFd, (struct sockaddr *)&svrAdd, sizeof(svrAdd)) < 0)
{
    cerr << "Cannot bind" << endl;
    return 0;
}

    listen(listenFd, 5);

    int noThread = 0;

    while (noThread < 3)
    {
        socklen_t len = sizeof(clntAdd);
        cout << "Listening" << endl;

    //this is where client connects. svr will hang in this mode until           client conn
        connFd = accept(listenFd, (struct sockaddr *)&clntAdd, &len);

        if (connFd < 0)
        {
            cerr << "Cannot accept connection" << endl;
            return 0;
        }
        else   
        {
            cout << "Connection successful" << endl;
        }

        pthread_create(&threadA[noThread], NULL, task1, NULL); 

        noThread++;
    }

    for(int i = 0; i < 3; i++)
    {
        pthread_join(threadA[i], NULL);
    }  
}

void *task1 (void *dummyPt)
{
    cout << "Thread No: " << pthread_self() << endl;
    char test[256];
    bzero(test, 256);
    bool loop = false;
    while(!loop)
    {       
        bzero(test, 256);     
        int n = read(connFd, test, 255);
        if (n < 0) error("ERROR reading from socket");
        printf("Here is the message: %s\n",test);            
    }
    cout << "\nClosing thread and conn" << endl;
    close(connFd);
}

和客戶端代碼

using namespace std;

int main (int argc, char* argv[])
{
    int listenFd, portNo;
    bool loop = false;
    struct sockaddr_in svrAdd;
    struct hostent *server;

    if(argc < 3)
    {
        cerr<<"Syntax : ./client <host name> <port>"<<endl;
        return 0;
    }

    portNo = atoi(argv[2]);

    if((portNo > 65535) || (portNo < 2000))
    {
        cerr<<"Please enter port number between 2000 - 65535"<<endl;
        return 0;
    }       

    //create client skt
    listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    if(listenFd < 0)
    {   
        cerr << "Cannot open socket" << endl;
        return 0;
    }

    server = gethostbyname(argv[1]);

    if(server == NULL)
    {
        cerr << "Host does not exist" << endl;
        return 0;
    }

    bzero((char *) &svrAdd, sizeof(svrAdd));
    svrAdd.sin_family = AF_INET;

    bcopy((char *) server -> h_addr, (char *) &svrAdd.sin_addr.s_addr, server -> h_length);

    svrAdd.sin_port = htons(portNo);

    int checker = connect(listenFd,(struct sockaddr *) &svrAdd, sizeof(svrAdd));

    if (checker < 0)
    {
        cerr << "Cannot connect!" << endl;
        return 0;
    }

    //send stuff to server
    for(;;)
    {
        char s[300];
        //cin.clear();
        //cin.ignore(256, '\n');
        cout << "Enter stuff: ";
        bzero(s, 300);
        cin.getline(s, 300);

        write(listenFd, s, strlen(s));
    }
}

Yor connFd是一個全局變量,您可以從主線程和所有處理線程中進行訪問。 這不會做! 想象一下-您已經接受了第一個連接並將變量設置為接收套接字。 您已經生成了處理線程,該線程開始讀取。 接下來您知道,另一個連接即將到來,您也將收到它! 此刻connFd指向新連接,因此已經在使用它的線程將突然切換到新連接! 當然不好。

解決此問題的方法是以不跨線程共享的方式將連接傳遞給線程。 最簡單的方法是使用C ++線程類。

例如,下面的代碼片段說明了上述想法:

void handle_connection(int fd) {
   ... <your task1 code>
}

... 
std::vector<std::thread> threads;
...
int conn = accept(listenFd, (struct sockaddr *)&clntAdd, &len);
threads.push_back(std::thread(&handle_connection, conn));
...

... (in the end)
for (auto&& t : threads)
    t.join();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM