구현 | 서버제어

서버의 실행

select 함수를 실행한 뒤 각 서버의 run 함수를 호출하게 되는데, 서버의 run 함수는 자신이 연결되어 있는 커넥션들에 대해 입출력 작업을 최대 1회까지만 실행할 수 있습니다. select 함수의 결과로 read/write fd_set이 말하는 것은 1번 입출력이 가능한지에 대한 여부이기 때문입니다. 즉, 서버는 자신의 커넥션들에 대해 1번 순회하는 것이 1사이클입니다. 각 서버가 1사이클씩 돌면 manager 단에서 select 함수를 다시 실행하고, 또 서버들은 1사이클씩 도는 과정이 계속해서 반복되는 것입니다. 코드는 아래와 같습니다.

std::map<int, Connection>::iterator it = m_connections.begin();
while (it != m_connections.end())
{
	std::map<int, Connection>::iterator it2 = it++;
	int fd = it2->first;

	if (m_fd == fd)
		continue ;
		try {
			if (hasSendWork(it2->second))
			{
				runSend(it2->second);
				continue ;
			}
			if (hasExecuteWork(it2->second))
			{
				runExecute(it2->second);
				continue ;
			}
			if (hasRequest(it2->second)) {				
				runRecvAndSolve(it2->second);
			}
		} catch (Server::IOError& e) {
			ft::log(ServerManager::log_fd, ft::getTimestamp() + e.location() + std::string("\n"));
			closeConnection(fd);
		} catch (...) {
			ft::log(ServerManager::log_fd, ft::getTimestamp() + "detected some error" + std::string("\n"));
			closeConnection(fd);				
		}
}

커넥션 관리

같은 이유로 새로운 커넥션(클라이언트)을 추가하는 작업도 해당 서버의 커넥션 순회가 끝난 뒤에 처리합니다. 새롭게 연결한 클라이언트 소켓도 read fd_set에 등록되어 select 함수를 실행한 뒤 결과에 따라 요청을 읽어야 하기 때문에, 커넥션을 순회하기 전에 위치하면 처리 흐름이 직관적이지 않습니다. 한 번의 select 함수로 동시에 감시할 수 있는 소켓의 수는 1024개이고, 서버는 여러 개 생성될 수 있는 반면 디스크립터 테이블은 공유하기 때문에 현재 연결된 커넥션이 많은 경우에는 새로운 연결을 받지 않던가 한가한 커넥션을 끊고 연결해야 합니다.

if (hasNewConnection())
{
	if (m_connections.size() >= (1024 / m_manager->get_m_servers().size()))
	{
		int fd = getUnuseConnectionFd();
		if (fd == -1)
			return ;
		closeConnection(fd);
	}
	if (!acceptNewConnection())
		reportCreateNewConnectionLog();
}

Last updated

Was this helpful?