TCP 소켓 서버 Accept 부분 질문입니다.

l595659의 이미지

MFC로 만든 소켓 서버 및 클라이언트 프로그램을 Class 화 하여 바꿔보고 테스트 해보고있습니다.

처음엔 acccept / recv 까진 잘 되다가 다음 메세지를 보내려고 해도 accept에서 멈춰있네요
accept에서 건드려보면 accept에서 안멈추고 recv로 넘어가서 다른클라이언트가 못들어가구요

어떻게 수정해야할지 감이 안잡히네요..

MFC에다가 적용하기전에 콘솔로 해보는 중인데 문제가 많네요..

헤더파일 입니다.

#pragma once
#include "Winsock.h"
#include <stdio.h>
#include <vector>
#include <atlstr.h>
 
#pragma comment(lib, "ws2_32.lib")
 
#define MAX_CLIENT_NUM 255
#define _CRT_SECURE_NO_WARNINGS
#define BUFSIZE 255
#define BUFFER_SIZE 255
class TCPServer
{
public:
 
	TCPServer();
	~TCPServer();
	struct UserData {
		char Ip_Address[16];
		char port[10];
		char strConnTime[30]; //DB에 보낼 접속시간 변수
		char strCloseTime[30];
	};
	UserData m_user_list[MAX_CLIENT_NUM + 1];
 
	SOCKET server_sock; //샘플
	SOCKADDR_IN serv_socketAddr; //샘플
 
	SOCKET clnt_sock;
	SOCKADDR_IN clnt_socketAddr;
 
	//---------------------------------------------------//
	CString slniPath;
	TCHAR ServerPort[MAX_PATH];
	TCHAR ClientCount[MAX_PATH];
 
	int index;
	int ServerPort_Num;
	int ClientCount_Num;
	int size;
	//--------recv 관련---------//
	char readbuffer[BUFSIZE];
	int recvsize;
	CString strRecvTime;
	CString strMsg;
	//--------------------------//
 
 
 
	std::vector<SOCKET> client_list;
	std::vector<SOCKADDR_IN> udpClient_list;
	//---------------------------------------------------//
	void socketAndAddrInit(SOCKET servSock, SOCKADDR_IN serv_sockAddr, SOCKET clntSock, SOCKADDR_IN clnt_sockAddr); //다른곳의 socket 등을 header 파일 안의 소켓으로
	void portClntCountInfo(CString iniLocation, CString serverSection, CString portKey, CString clientNumKey); //ini 파일 내용 가져오기
	int winsockInit();
	void serverSocket(int domain, int type, int protocol);
	void servSockAddr(int domain);
	int beforeAccept();
	void clntSockAddr(int domain);
	int clntAccept();
 
	void multiClient();
	//---------------------------------------------------//
	void servRecvfrom();
	void servSendto();
};
void TCPServer::socketAndAddrInit(SOCKET servSock, SOCKADDR_IN serv_sockAddr, SOCKET clntSock, SOCKADDR_IN clnt_sockAddr)
{
	servSock		= server_sock;
	serv_sockAddr	= serv_socketAddr;
	clntSock		= clnt_sock;
	clnt_sockAddr	= clnt_socketAddr;
}
 
void TCPServer::portClntCountInfo(CString iniLocation, CString serverSection, CString portKey, CString clientNumKey)
{
 
	//CString section;
 
	slniPath.Format(iniLocation);
	GetPrivateProfileString(serverSection, portKey, _T(""), ServerPort, MAX_PATH, slniPath);
	ServerPort_Num = _ttoi(ServerPort);
 
	GetPrivateProfileString(serverSection, clientNumKey, _T(""), ClientCount, MAX_PATH, slniPath);
	ClientCount_Num = _ttoi(ClientCount);
}
 
int TCPServer::winsockInit()
{
	WSADATA wsaData;
	if (int retval = WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		printf("winsockInit() Error");
	return 0;
}
 
void TCPServer::serverSocket(int domain, int type, int protocol)
{
	server_sock = socket(domain, type, protocol);
	if (server_sock == SOCKET_ERROR)
	{
		printf("ServerSocket() Error");
	}
}
 
void TCPServer::servSockAddr(int domain)
{
	serv_socketAddr = { 0 };
	serv_socketAddr.sin_family = domain;
	serv_socketAddr.sin_port = htons(ServerPort_Num);
	serv_socketAddr.sin_addr.s_addr = htonl(INADDR_ANY);
}
 
int TCPServer::beforeAccept()
{
	int retval = bind(server_sock, (SOCKADDR*)&serv_socketAddr, sizeof(SOCKADDR));
	if (retval == SOCKET_ERROR)
	{
		//printf("ServerBind() Error");
		return 0;
	}
 
	listen(server_sock, ClientCount_Num);
}
 
void TCPServer::clntSockAddr(int domain)
{
	clnt_socketAddr = { 0 };
	clnt_socketAddr.sin_family = domain;
	clnt_socketAddr.sin_port = htons(ServerPort_Num);
	clnt_socketAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 
	size = sizeof(SOCKADDR_IN);
}
 
int TCPServer::clntAccept()
{
 
	clnt_sock = accept(server_sock, (SOCKADDR*)&clnt_socketAddr, &size);
	if (clnt_sock == SOCKET_ERROR)
	{
		printf("clntAccept() Error");
		return 0;
	}
}
//-------------------ACCEPt-------------------
//-------------------수정 필요------------------
void TCPServer::multiClient() {
	client_list.push_back(clnt_sock);
	strcpy_s(m_user_list<ol>
</ol>
.Ip_Address, inet_ntoa(clnt_socketAddr.sin_addr));
}
 
void TCPServer::servRecvfrom()
{
	recvsize = recv(clnt_sock, readbuffer, BUFSIZE, 0);
	readbuffer[recvsize] = '\0';
	strMsg = CString(readbuffer, recvsize);
	printf("%s", strMsg);
	strMsg = "";
}
 
void TCPServer::servSendto()
{
	for (int i = 0; i < client_list.size(); i++) {
 
	}
}

CPP 파일 입니다.

// ServerClass.cpp : 이 파일에는 'main' 함수가 포함됩니다. 거기서 프로그램 실행이 시작되고 종료됩니다.
//
 
#include <iostream>
#include "ServerClass.h"
 
TCPServer::TCPServer() {};
TCPServer::~TCPServer() {};
 
SOCKET server_socket; //샘플
SOCKADDR_IN servSocketAddr; //샘플
 
SOCKET clnt_socket;
SOCKADDR_IN clntSocketAddr;
 
 
int main()
{
	TCPServer tcpserver;
 
	tcpserver.socketAndAddrInit(server_socket, servSocketAddr, clnt_socket, clntSocketAddr);
 
	tcpserver.portClntCountInfo(_T("./NetworkPath.ini"), _T("ServerInfo"), _T("Port"), _T("ClientCount"));
	tcpserver.winsockInit();
 
	tcpserver.serverSocket(AF_INET, SOCK_STREAM, 0);
 
	tcpserver.servSockAddr(AF_INET);
 
	tcpserver.beforeAccept();
 
	while (1)
	{
#if 1
		tcpserver.clntSockAddr(AF_INET);
#endif
		tcpserver.clntAccept();
		if (tcpserver.clnt_sock == SOCKET_ERROR) 
		{
			break;
		}
 
		tcpserver.multiClient();
		tcpserver.index++;
 
//---------------------------------
 
		tcpserver.servRecvfrom();
		if (tcpserver.recvsize <= 0)
		{
			break;
		}
 
	}
 
 
}
라스코니의 이미지

accept()는 새로운 클라이언트가 접속할 때까지 대기하는 함수입니다만...

라스코니의 이미지

살펴보니 "tcp" server를 구현하시려고 하는 것으로 보이고 multiple clients 연결을 지원해야 하시려고 보네요.

주제넘게 조언을 드리자면 현재의 구조로는 하나의 client만 처리할 수 있습니다. UDP와 TCP는 다르기 때문에 이전 그대로 개념을 가져오면 안됩니다.

multiple clients를 지원하는 tcp server는 크게 fork()를 쓰는 것과 select()를 사용하는 방법으로 구분할 수 있습니다. 이 방법은 서로간에 큰 차이가 있으니 꼭 구글링을 통해 공부를 하시고 서버 구조를 설계해 보세요.

가장 좋은 방법은 아마 select를 사용하는 인터넷 예제를 완벽히 이해하고 진행하는 것일 겁니다.

l595659의 이미지

select를 사용하는것으로 찾아봐야겠네요
MFC로 만들때는 다중ㅈ 클라이언트가 되었는데 class 화 시켜서 하니까 하나의 클라이언트만 처리하길래 뭔가 했네요

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.