Здравствуйте. У меня такой вопрос возник:
Необходимо сделать 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;
}
Многопоточное клиент-серверное приложение
Необходимо сделать 3 клиент-серверных приложения, работающих по схемам:
1кл - 1 св
1кл - N св
N св - 1 кл.
с первыми двумя задачами справился. Теперь второй день бьюсь над третьей задачей. Подскажите, как правильно добавить функцию ожидания соединения клиентов accept и сформировать новые потоки, используя функцию CreateThread.
Вот код программы сервера: (заранее извиняюсь, если привел лишний код)
Код:
А какая разница между 2 и 3? От перестановки слагаемых имхо..