Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Многопоточное клиент-серверное приложение

43K
17 декабря 2011 года
outburst
1 / / 29.10.2008
Здравствуйте. У меня такой вопрос возник:
Необходимо сделать 3 клиент-серверных приложения, работающих по схемам:
1кл - 1 св
1кл - N св
N св - 1 кл.
с первыми двумя задачами справился. Теперь второй день бьюсь над третьей задачей. Подскажите, как правильно добавить функцию ожидания соединения клиентов accept и сформировать новые потоки, используя функцию CreateThread.
Вот код программы сервера: (заранее извиняюсь, если привел лишний код)
Код:
Здравствуйте. У меня такой вопрос возник:
Необходимо сделать 3 клиент-серверных приложения, работающих по схемам:
1кл - 1 св
1кл - N св
N св - 1 кл.
с первыми двумя задачами справился. Теперь второй день бьюсь над третьей задачей. Подскажите, как правильно добавить функцию ожидания соединения клиентов accept и сформировать новые потоки, используя функцию CreateThread.
Вот код программы сервера: (заранее извиняюсь, если привел лишний код)
BOOL CTcp_serverDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon
   
    // TODO: Add extra initialization here
    m_String = "";
    /* Изначально сервер не запущен */
    INIT = false;
    is_accept = false;
    m_ServerAddress = SERVER_ADDRESS;
    m_ServerPort = SERVER_PORT;
    UpdateData(FALSE);
    return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTcp_serverDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CTcp_serverDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTcp_serverDlg::OnQueryDragIcon()
{
    return (HCURSOR) m_hIcon;
}

/* Функция, отвечающая за начало работы сервера */
void CTcp_serverDlg::OnStartServer()
{
    /* Если серввер уже включен, то не надо снова решистрировать сокет */
    if(INIT)
        return;
    INIT = true;
    /* Вызов библиотечной функции, отвечающей за работу с сокетами.
    Если не загрузить эту библиоетку, то любой вызов сетевой функции вернет ошибку
    WSANOTINITIALISED*/
    WSADATA wsaData;
   
    /*если библиотека на загружена, сказать об этом пользователю */
    if (WSAStartup(0x0101, &wsaData))
    {
        MessageBox("Error. Load Neccecary Libraray");
        WSACleanup();
    }
    /* Регистрируем сокет сервера */
    servsocket = socket(PF_INET,SOCK_STREAM,DEFAULT_PROTOCOL);
    if (servsocket == INVALID_SOCKET)
        MessageBox("Error. Create socket :-(\n");

    /* Регистрируем сокет в системе.
    Заполнение структуры с адресом сервера и номером порта */
    SOCKADDR_IN socketaddr;
    socketaddr.sin_family = AF_INET;
    socketaddr.sin_addr.s_addr  = inet_addr (m_ServerAddress);
    socketaddr.sin_port = htons (m_ServerPort);
    bind(servsocket,(LPSOCKADDR)&socketaddr,sizeof(socketaddr));
    int Errors;

    /* Прослушивание сокета. Ожидание подключения клиентов */
    Errors = listen(servsocket,2);
    if (Errors == SOCKET_ERROR)
        MessageBox(" Proslushivanie ne udalos !!!");

    /* Переводим сокет в неблокирующий режим, чтобы не блокировать процесс программы */
    int r = WSAAsyncSelect(servsocket,m_hWnd,1777, FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
    m_String = "";
    m_History.InsertString(0,"Server started");
    UpdateData(FALSE);
    /* Посылка сообщения клиенту о работающем сервере */
    OnSend();
}

/* Функция, отвечающая за остановку работы сервера */
void CTcp_serverDlg::OnStopServer()
{
    INIT = false;
    is_accept = false;
    m_String = "Server stopped";
    UpdateData(FALSE);
    /* Посылка сообщения клиенту об остановке сервера */
    OnSend();
    /* Удаление сокета, освобождение ресурсов системы */
    closesocket(servsocket);
    WSACleanup();
    m_History.InsertString(0,"stop server");
}

/* Функция OnSend(): Посылка сообщения клиенту*/
void CTcp_serverDlg::OnSend()
{
    /* Обработка строки из поля ввода */
    UpdateData();
    m_String +=  "\n";
    int len = m_String.GetLength();
    /* Посылка строки */
    len = send( client, m_String, len, 0) ;
    m_String = m_String.Left(m_String.GetLength()-1);
    UpdateData(FALSE);
    m_History.InsertString(0,m_String);
    /* Очистка поля ввода */
    m_String = "";
    UpdateData(FALSE);
}

/* Функция OnDestroy(): Экстренное завершение работы сервера */
void CTcp_serverDlg::OnDestroy()
{
    OnStopServer();
    CDialog::OnDestroy();
}

/* Функция OnServerAccept(): реакция на события для сокета сервера */
afx_msg LRESULT CTcp_serverDlg::OnServerAccept(WPARAM wParam, LPARAM lParam)
{
    if (WSAGETASYNCERROR(lParam))
    {
        AfxMessageBox("Error detecting Client");
        return 0L;
    }
    int recvd;
    CString str;
    /* Реакция на различные события сокета */
    switch(WSAGETSELECTEVENT(lParam)){
    case FD_READ:
        char cstr[BUFLEN];
        /* Получение строки от клиента */
        recvd = recv (client, cstr, BUFLEN , 0);
        /* Если получены данные */
        if(recvd>0){
            /* Обрабатываем строку */
            str = cstr;
            int n=str.Find("\n");
            str.Delete(n,BUFLEN-n+3);
            if(str == "Disconnected"){
//              str += " is disconnected";
            //INIT = false;
            }

            /* Вывод строки в начало списко сообщений */
            m_History.InsertString(0,str);
            /* Если окно неактивно, сделать его мигающим в Панеле задач */
            this->FlashWindow(TRUE);
        }
        else
            m_History.AddString("not receive");    
        break;
    case FD_CLOSE:
        /* Если сокет работа клиента завершена, то закрыть сокет клиента */
        recvd = shutdown(client,SD_BOTH);
        is_accept = false;
        closesocket(client);
        client = 0;
        break;
    case FD_ACCEPT:
        UpdateData();
        SOCKADDR_IN socketaddr;
        int len;
        len = sizeof(socketaddr);
        //if (!INIT)
        //{
        /* При попытке соединиться с сервером создаем сокет для клиента */
        SOCKET temp_socket = accept(servsocket, (sockaddr*) &socketaddr, &len );
        /* Если это тот же самый клиент, что уже присоединен к серверу */
        if(client==temp_socket)
            /* Выйти из функции, не внося никаких изменений */
            return 1;
        else if(is_accept)
            return 1;
        is_accept = true;
        /* Иначе сделать текущим клиентом новый, последний из полключившихся */
        client = temp_socket;
        /* Вывод сообщения о подключении клиента */
        //client = accept(servsocket, (sockaddr*) &socketaddr, &len );
    //INIT = true;
            char* ch = inet_ntoa(socketaddr.sin_addr); 
        CString str = "client ";
        str += ch;
        str += " is connected";
        m_History.InsertString(0,str);
        str = "Server started\n";
        if (client != SOCKET_ERROR){
            /* Посылка сообщения о работающем сервере клиенту */
            len = send( client, str, str.GetLength(), 0) ;
        }
        else
            m_String = "SOCKET_ERROR";
        break;
    }
    //return 1;
}
14
18 декабря 2011 года
Phodopus
3.3K / / 19.06.2008
А какая разница между 2 и 3? От перестановки слагаемых имхо..
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог