소켓 통신 할때 , 속도 향상 방법은 없을까요 ?
서버가 양쪽의 메세지를 중계해 주고 있습니다.
예를들어서, 메신저 처럼 1:1 파일 전송을 합니다.
select 로 recv 처리를 합니다만, 이때 sec=0 , usec=1 로
주어서 설정하면, 속도가 직접 붙는 것보다 너무 차이가 많이
납니다.
그래서 아예, usec=0 으로 처리하면, 상당히 빠릅니다만,
문제는 프로세스를 많이 사용하는것 입니다.
예를 들엇
while(1)
{
if( select..A )
{ recv.. A , send B}
if ( select B )
{ recv B , send A }
}
중간에 아무 패킷이 없다면, 말그대로 계속 돌게 됩니다.
시간을 적절히 체크해서 , 노는 시간이 혹시 3초가 넘으면
딜레이 주는 코드를 줍니다..
while(1)
{
if( select..A )
{ recv.. A , send B}
if ( select B )
{ recv B , send A }
if ( 3초가 초과되면,,)
{
usleep(1);
}
}
이렇게 되면, select A , select B 를 만나서 해당 시간을 리셋하기
전에는 무조건 usleep(1)을 통과하기 때문에, 문제가 없습니다.
그런데, usec=0 으로 했을때도 직접 전송하는것보다는 많은 차이가
있습니다.
어떻게 해결 하면 좋을까요 ?
TCP_NODELAY.. 등은 주었지만 도움이 않됩니다.
어쩌면 잘 못 사용했을지도 모릅니다.
바인딩 하는 소켓은..
socket 생성후 , 해당 소켓에 SO_KEEPALIVE 을 주었고,
이후, TCP_NODELAY 을 주었습니다 , 둘다 옵션은 1 입니다.
접속하는 소켓은
socket 생성후 해당 소켓에
SO_LINGER 을 l_onoff=1 , l_linger=0 을 주었습니다.
그리고, TCP_NODELAY에 1을 주고 사용합니다.
더이상의 속도 향상은 불가능 할 것인지 잘 모르겠습니다.
네트웍 이 한단계(두단계(?)) 거친다고 이해 하더라도 좀 느립니다.
더이상의 속도 향상은 힘들까요 ????
혹시, 이런일이 있다면, 어떤 다른 방법을 통해서 향상 시킬수
없을까 생각하며 , 질문을 올립니다.
좋은 주말 보내시기 바랍니다.
첨부 | 파일 크기 |
---|---|
unix08C_199703025.c | 964바이트 |
질문내용을 이해하건데, select 할때 두 소켓을 동시에 하지 않고 따
질문내용을 이해하건데, select 할때 두 소켓을 동시에 하지 않고 따로 따로 하나봅니다. 두 개를 동시에 select 하세요..
---
http://coolengineer.com
답글 감사드립니다.말씀하신것처럼 따로 따로 select 하는것이
답글 감사드립니다.
말씀하신것처럼 따로 따로 select 하는것이 맞습니다.
혹시, 한번에 한다면, 어떻게 한번에 할 수 있을지 잘 모르겠습니다.
FD_SET 할때, 소켓 포인터를 하나를 주는 것이 아니라, 두개를
주는것인지 ???
잘 이해가 않되는 부분이,
FD_SET 에서, 두개의 소켓을 알려 줄 수 있는 방법을
잘 모르겠습니다.
예를 들어 소켓 포인터가
int t( int *socket_pointer , int *socket_pointer2)
{
fd_set fd_set_s;
......중략
FD_SET ( *soket_pointer , &fd_set_s );
FD_SET ( *soket_pointer2 , &fd_set_s );
select ( FD_SETSIZE , &fd_set_s ....... );
if( FD_ISSET( *soket_pointer , &fd_set_s ) )
{
recv......
}
if( FD_ISSET( *soket_pointer2 , &fd_set_s ) )
{
recv......
}
이렇게 하면 select 한번만 이용하는 것이 맞을 까요 ?
그런데, FD_SET 을 이렇게 두번 해도 되나요 ????
한수 부탁드립니다.
:)
도움이 될까 모르겠습니다.
select 함수 쓰는 방법에 관한 문제인 것 같네요요
첨부 파일에 간단하게 select함수를 구현한 예제 프로그램이 있습니다. 참고하시고...
select 함수를 쓰는 이유가 cpu 점유율이 낮아서 입니다. 그냥 while문보다는 훨씬 적게 쓰는 걸루 알고있습니다. (M$windog에서의 이벤트리스너 정도)
FD_ZERO(fd_set* fdset); 으로 초기화 시킨 다음
만약 내가 관심있는 것이 sock1, sock2라면
FD_SET(sock1, fdset);
FD_SET(sock2, fdset);
하시고
while문 실행전에 fd_set temp;라는 임시 저장 공간을 만들어 놓습니다. while문을 돌 때마다 비트값이 변경되므로 내가 검사하고싶은 비트순위가 바뀌면 다시 원래의 내가 관찰하고 싶은 값을 알 수가 없으므로... while문 안에 맨처음에 복사하는 루틴을 넣어둡니다. temp = fdset;
그리고 난 후,
retval = select(8(몇개까지 관찰하고싶은가), temp(읽을 것이 있나), NULL(쓸 곳이 있나), NULL(에러난 곳이 있나), struct timeval *timeout);
하시면 될 겁니다.
속도를 증가시키고 싶으면 보낼때마다 받을 수 있는지 체크하지않고 일방적으로 보내기만해도 되니까 보내는 쪽의 읽는 소켓을 닫아버리고 받는 쪽의 쓰는 소켓을 닫아버리면 좀 더 빨라집니다.
남으로 창을 내겠소.
밭이 한참갈이 괭이로 파고 호미론 김을 메지요.
구름이 꼬인다 갈리있소. 새들의 노래는 공으로 들으랴오.
강냉이가 익거든 와자셔도 좋소.
왜 사냐건 웃지요.
select()를 보다 자세히 보셔야 할 듯 합니다.예) 현재 열
select()를 보다 자세히 보셔야 할 듯 합니다.
예) 현재 열린 파일 디스크립터가 {0,1,2,3,4,5,6,9,7} 라고 가정
" 파일이 9개가 열려 있는데, 입력이 어디서 발생했는지 알려면 어떻게 하지?"
- 8은 일부러 뺐으며, 소팅도 안했음, 만일 통신 서버라면, 접속은 순서대로 예측되지만, 끊는거야 클라이언트 맘대로 이걸랑......
- 이글을 읽는 사람이, 이미 소켓도 파일임을 알고 있다고 가정한다.
1) fd_set 비트벡터에 각 파일 디스크립터를 세팅
fd_set readset;
FD_ZERO(&readset);
FD_SET(0, &readset);
FD_SET(1, &readset);
...
FD_SET(7, &readset);
2) 최대 디스크립터 번호를 구한다? 여기서는 "9" ==> maxfd라는 변수에 넣었다.
3) select ( maxfd+1, &readset, 0, 0, &timeout);
- +1을 한것에 유의한다.
- 이 함수에서 탈출했다(리턴했다)함은, 다음 3-1~3-3중 하나이다.
3-1) readset에서 이벤트 발생, 즉, 입력이 발생, { 0,1,2,3,4,5,6,9,7 } 중에 하나 이상에서 입력이 발생했다(OS왈). 그러나, 어느 디스크립터 인지는 프로그래머가 알아볼것!(OS왈, FD_ISSET이용).
3-2) timeout이 발생했다!(OS왈)
3-3) 시그널이 수신되었다.(OS왈)
- select에서 얌전히 이벤트가 발생되기를 기다리는데, 오라고 하는 이벤트(입력이벤트)는 안오고, 시그널이 도착되었다.
- 시그널? 에러이거나, 아니면 내 프로그램상에서는 에러는 아니지만, 그냥 시그알람이건 시그파이프건 뭐 임의의것이 도착했다. 어쩌면, 프로그래머가 Ctrl+C로 시그널을 보낸것인지도....
4) 3-1~3-3에 맞는 핸들러를 모두 각각 달아준다.
- 약식으로 3-1만 대충써보면 다음과 같다.
if ( FD_ISSET(0, &readset) ) // 0번 파일에서 입력있니?
if ( FD_ISSET(1, &readset) ) // 1번 파일에서 입력있니?
...
if ( FD_ISSET(7, &readset) ) // 7번 파일에서 입력있니?
-3-2, 3-3은 ? 고민해 본다.
* 전산하는사람
1)과 4)에서 이렇게 나열하는거 싫어진다. 당연히, 현재 열린 파일을 관리하기 위한 자료구조와 루프를 머리에 떠올리게 된다.
참고로 fd_set readset;에 대해 몇가지 언급하면.fd_
참고로 fd_set readset;에 대해 몇가지 언급하면.
fd_set은 비트벡터입니다.
비트 필드라고 보시면 되겠습니다.
한 비트는 한개의 파일디스크립터로 묘사됩니다.
FD_SET()매크로는 readset이라는 비트벡터중 한 비트를 세팅하는 것이고,
FD_ISSET()은 비트벡터중에 한 비트가 1인지(아님0이겠지)를 판단해주는 매크로입니다.
보통 대부분의 시스템에서 1024비트를 가지며(그러나, alignment/padding등의 사유로 보다 큰 크기를 가질 수 있습니다.)
이는 다른 말로 최대 1024개의 파일에 대해 수행된다는 것을 의미하기도 합니다.
* 왜? 정수로 안했지?
=> 아마도, 절약정신이 아닐까? 합니다. 커널에게 만일 1024개의 정수(파일디스크립터를 날린다면; 4*1024=4KB)를 날린다면, 오버헤드가 크지 않을까? 해서 인듯합니다만, 믿을 수 없는 추측이라는......... :twisted:
답글 감사드립니다.바쁘실 텐데 불구하고, 자세한 설명은 큰 도움이
답글 감사드립니다.
바쁘실 텐데 불구하고, 자세한 설명은 큰 도움이 되었습니다.
좋은 한 주 보내세요.
댓글 달기