c언어, 네트워크 프로그래밍에서 여러 가지의 메세지를 받을 때 생기는 문제에 대해서 질문있습니다.

balgarac1의 이미지

typedef struct _dgt_auth_req_msg
{
	UB2 msg_type;
	SCHAR db_user[33];
	SCHAR password[33];
	SCHAR program_name[33];
	SCHAR db_name[33];
}dgt_auth_req_msg; // msg type 1
 
typedef struct _dgt_auth_res_msg
{
	UB2 msg_type;
	UB2 rtn_len;
	SCHAR rtn_msg[257];
}dgt_auth_res_msg; // msg type 2
 
typedef struct _dgt_sql_req_msg
{
	UB2 msg_type;
	UB4 sql_len;
	SCHAR sql_text[1025];
	UB2 sql_type;
}dgt_sql_req_msg; // msg type 3
 
typedef struct _dgt_sql_res_msg
{
	UB2 msg_type;
	UB4 rtn_len;
	SCHAR rtn_data[1025];
	UB2 sql_type;
}dgt_sql_res_msg; // msg type 4

서버와 클라이언트에서의 프로토콜 입니다.

msg_type은

#define UB2 unsigned short
#define UB4 unsigned int
#define SCHAR signed char
 
#define auth_req_msg 1
#define auth_res_msg 2
#define sql_req_msg 3
#define sql_res_msg 4
#define close_req_msg 5

이렇게 되어 있습니다.

서버는 select로 되어 있습니다.

제가 궁금한 부분은

void CNetwork::gateway_Select()
{
	int nIdx;
	while(true)
	{
		cpy_reads = reads;
		timeout.tv_sec = 5;
		timeout.tv_usec = 5000;
 
		if((fd_num = select(fd_max + 1, &cpy_reads, 0, 0, &timeout)) == -1)
		{
			cout << "gateway_Select() select error" << endl;
			break;
		}
 
		if(fd_num == 0)
			continue;
 
		for(nIdx = 0; nIdx < fd_max + 1; nIdx++)
		{
			if(FD_ISSET(nIdx, &cpy_reads))
			{
				if(nIdx == nSock) // request connection.
				{
					adr_sz = sizeof(clnt_addr);
					nSock = socket(PF_INET, SOCK_STREAM, 0);
					nClntSock = accept(nSock, (struct sockaddr *)&clnt_addr, &adr_sz);
					FD_SET(nClntSock, &reads);
 
					if(fd_max < nClntSock)
					{
						fd_max = nClntSock;
						cout << "connected client.." << endl;
					}
				}
				else
				{
 
					int nCnt = 0;
					str_len = recv(nIdx, buf + nCnt, BUFSIZ, 0);
					if(str_len == -1)
						cout << "gateway_Select() recv error.." << endl;
 
					nCnt += str_len;
 
					switch()
					{
						case auth_req_msg: // 1
							nPacketSize = 134;
							break;
						case auth_res_msg: // 2
							nPacketSize = 261;
							break;
						case sql_req_msg: // 3
							nPacketSize = 1033;
							break;
						case sql_res_msg: // 4
							nPacketSize = 1033;
							break;
						case close_req_msg: // 5
							nPacketSize = 2;
							break;
						case close_res_msg: // 6
							nPacketSize = 261;
							break;
						default :
							break;
					}
 
					if(nCnt < nPacketSize)
					{
						while(nCnt < nPacketSize)
						{
							str_len = recv(nIdx, buf + nCnt, BUFSIZ, 0);
							if(str_len == -1)
								cout <<"gateway_Select() recv 2st error" << endl;
 
							nCnt += str_len;
						}
 
						;
					}
				}
 
				gateway_MsgService(nIdx, buf);
			}
		}
	}
}

switch() 이 안에 들어가야 할 것이 무엇인지 잘 모르겠습니다. ㅜ

shint의 이미지

UB2 msg_type; 가 들어가야 하네요.

typedef struct _dgt_auth_req_msg
{
UB2 msg_type; <-------------------메시지 크기
SCHAR db_user[33];
SCHAR password[33];
SCHAR program_name[33];
SCHAR db_name[33];
}dgt_auth_req_msg; // msg type 1 <----------- 1바이트로 착각??

이 주석을 보면. 언뜻. 1바이트로 착각하게 됩니다.

//---------------------------------------------------------------------------

//switch()는 4바이트로 알고 있습니다.
//하지만. __int64 도 해보니 되네요?? 확인해봐야 할거 같습니다.

int i=1234567890;
switch(i)
{
case 1234567890: //1234567890
printf("%d\n", i);
break;
case 12345678901: //-539222987
printf("%d\n", i);
break;
}

__int64 i=1234567890123456789;
switch(i)
{
case 1234567890123456789: //1234567890123456789
printf("%I64d\n", i);
break;
case 12345678901234567890: //-6101065172474983726
printf("%I64d\n", i);
break;
}

댓글 첨부 파일: 
첨부파일 크기
Package icon test switch()에 인자값 크기.zip381.84 KB

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

balgarac1의 이미지

감사드립니다. ㅜㅜ

jick의 이미지

1. 뭐 연습삼아 해보는 거라면 큰 상관은 없지만, recv가 -1을 돌려줄 경우 처리가 제대로 안되어 있네요. 그냥 에러메시지 한줄 찍은 다음에는 코드가 혼돈의 카오스에 빠질 듯.

2. 마찬가지로 클라이언트가 접속을 종료해서 recv가 0을 돌려줄 경우 처리가 안되어 있군요. 무한루프에 빠질 듯?

3. BUFSIZ가 얼마인지는 모르지만 recv를 처음 부를 때도 BUFSIZ만큼 읽을 수 있다고 하고, 버퍼에 50바이트가 쌓여 있어도 BUFSIZ만큼 읽을 수 있다고 하는데 과연 버퍼의 크기는?

4. recv가 메시지 하나보다 더 많은 양을 읽어서 돌려줄 경우 앞 메시지 하나만 읽고 나머지 부분은 버퍼에 담아두었다가 다음번에 읽을 때 사용해야 하는데 그 부분이 없는 것 같군요. (만약 클라이언트가 항상 메시지를 하나씩만 보내고 서버의 응답을 받은 다음에야 다음 메시지를 보낸다는 게 보장되면 이 부분은 없어도 될 수도 있습니다.)

5. 일어날 가능성이 제로에 가깝기는 하지만, 첫 recv가 단 한 바이트만 읽어서 돌려줄 수도 있습니다. 메시지 타입을 알기 위해서는 최소한 2바이트는 읽어야 하므로 이 경우 최소한 2바이트를 읽을 때까지 루프를 돌아야 합니다.

gilgil의 이미지

참고로 언급해 보자면 여기에서 출발한 패킷이 상대방에게 도착되는 동안 수많은 네트워크 장비를 거쳐서 가게 되는데, 특수한 장비에서는 L4 or L7 proxy를 돌리는 경우도 있습니다. 이 경우 packet level이 아닌 tcp data level로 데이터를 처리하게 되죠. 또한 tcp data의 수신측에서 제대로 된 처리를 하지 못하는 경우(recv하여 data를 소비시켜야 하는데 해당 thread가 어리버리해서 recv를 못하면) window size가 감소하여 network level에서 tcp data의 크기가 작아질 수도 있습니다. jick님이 말씀하신 부분(첫 recv가 단 한 바이트만 읽어서 돌려줄 수도 있습니)은 실제로도 충분히 일어날 수 있습니다. tcp는 순서만 보장해 줄 뿐이고, "송신한 바이트 수대로 수신이 될 것이다" 라는 것은 믿으시면 안됩니다.

balgarac1의 이미지

답글 감사합니다. 많은 도움이 됐습니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.