네트워크 프로그래밍에 대해 질문. client 쪽에 connection refu

mon12key의 이미지

TCP를 사용한 네트워크 프로그램으로, client와 server 사이의 중계 역활을 하는 프로그램을 작성하려 합니다. 이하 중개기라 부르겠습니다.
이 중계기는 clinet-server 입장에서는 단순히 proxy역활만 하는 것 처럼 보이게 하고 싶습니다.

client에서 연결 요청(connect())를 하게 되면 중계기에서는 요청을 listen()하고 있다고, 적절한 server가 있으면 중계기에서 accpet()를 하고, 적절한 server가 없으면 clinet쪽에 connection refuse 에러가 나도록 만들려 합니다.
그런데, connection refuse는 아예 listen 하고 있는 port가 없을때 나오는 에러 메세지여서, 이경우 중개기가 listen하고 있는 관계로 문제가 생깁니다.

낙엽의 이미지

질문의 요지가 무엇인지 잘 모르겠습니다만..

mon12key wrote:
TCP를 사용한 네트워크 프로그램으로, client와 server 사이의 중개 역활을 하는 프로그램을 작성하려 합니다. 이하 중개기라 부르겠습니다.
이 중개기는 clinet-server 입장에서는 단순히 proxy역활만 하는 것 처럼 보이게 하고 싶습니다.

client -- proxy -- server 이런 의미겠군요.

mon12key wrote:
client에서 연결 요청(connect())를 하게 되면 중개기에서는 요청을 listen()하고 있다고, 적절한 server가 있으면 중개기에서 accpet()를 하고, 적절한 server가 없으면 clinet쪽에 connection refuse 에러가 나도록 만들려 합니다.

1. client's ---> proxy (listen)
2. proxy --> server(적절한?..) 선택
3. client <---- ((proxy)) ----> server (proxy는 passing만)
이런 의미로 들리구요..

mon12key wrote:
그런데, connection refuse는 아예 listen 하고 있는 port가 없을때 나오는 에러 메세지여서, 이경우 중개기가 listen하고 있는 관계로 문제가 생깁니다.

이건.. 무슨의미죠? 지금 외근나가야 하니까 나중에 좀더 자세한 설명이 추가되어 있기를 바랍니다.
impactbar의 이미지

역활 : 역할의 잘못

중개 : 중개(仲介)
ꃃ제삼자로서 두 당사자 사이에 서서 일을 주선함. ¶중개 수수료/부동산 중개/그렇게 비축된 물건을 조합에서 사들여 팔거나 중개 또는 위탁 판매를 할 경우….≪이문구, 으악새 우는 사연≫ꄘ거간03(居間)①.ꄘ거매02(居媒).

중계 : 중계(中繼)[-계/-게]
ꃃ①중간에서 이어 줌. ¶산간 지대에서는 사단과 대대, 대대와 중대 사이의 교신이 잘 안되니까 중계 역할을 하는 곳이 필요하다. ②〖언론〗=중계방송①. ¶라디오 중계/텔레비전 중계. ③〖언론〗=중계방송②. ¶스포츠 중계/현장 중계.

mon12key의 이미지

^^;; 중개 -> 중계로 수정하였습니다.
논리적으로 글쓰기가 쉽지 않군요. 죄송합니다.
글쓰기 공부를 해야겠습니다. ^^;

우선 제가 만든 중계기(proxy 비스무리...) 는 listen()상태입니다.
이 중계기의 port로 client가 접속하였을때, 적절한 서비스가 있을때만
client로 접속을 허락하고 싶습니다.
현재 적절한 서비스가 있을때는 client에 적절한 서비스를 forward시키는데,
서비스가 없을때 client가 연결이 바로 안 끊기고 기다리고 있습니다.

listen하고 있는 소켓을 close()시키면 연결이 바로 끊기는데 이 방법 말고,
다른 방법으로 client쪽에 연결을 끊는 방법이 없을까요? client쪽에서는
"connect refuse" 에러 메세지가 나오도록.....

낙엽의 이미지

mon12key wrote:
listen하고 있는 소켓을 close()시키면 연결이 바로 끊기는데 이 방법 말고,
다른 방법으로 client쪽에 연결을 끊는 방법이 없을까요? client쪽에서는
"connect refuse" 에러 메세지가 나오도록.....

proxy쪽에서 client의 sockfd를 복사해서 가지고 있어야 겠군요..
proxy에서 연결은 계속 물고 있어야 할 겁니다. 대신 타임아웃을 걸어서 일정 시간이 지나면 연결은 끊어야 겠죠.

그리고 주기적으로 검사해서 해당 server가 active되었을 때, forwarding 해주는 방식이 있겠군요.

proxy 샘플을 하나 만들어 보고 다시 올려드리죠.

익명 사용자의 이미지

음... 꼭 connection refuse가 나와야 되나요? 그럴 이유가?
아무튼 이것이 좋은 방법은 아니지만 일단 설명해보겠습니다.

listen한 상태로 일단 있습니다.
accept전에 select ( RxD ) 를 걸어둡니다.
select가 걸리면 accept로 곧바로 가지 말고
서버쪽에 연결시도를 합니다.
연결이 되지 않으면 해당 listen소켓을 닫았다가 엽니다.
연결되면 accept를 하게 되면 되지 않을까라는
생각을 해봅니다.

해보지 않아서 잘 모르겠지만 그냥 추측이니까
믿지는 마세요.

펑키의 이미지

프락시 샘플은 쉽게 찾으실수 있을겁니다.
http//proxy.sourceforge.net
이것은 아주 간단한 샘풀이니 한번 참조해보세요.

접속 실패의 경우만..

1. 클라이언트 접속
2. 프락시에서 accept
3. 서버쪽에 접속(select timeout with non-block IO)
4. 서버쪽에 접속 실패(back to block IO/클라이언트 접속 해제)

구성할수있는 경우는 상당히 다양합니다. 아주 일반적인 서버 구성일수도 있습니다. 여기서 조금(상당히) 발전하면 미들웨어일수도 있구요. 너무 어렵게 생각하지 마시고 한번 시도해보시는게 어떨까요.?

다만 connection refuse를 클라이언트에게 전달해주는것은 다른 방법으로 해서 메시지를 넘겨주는건 어떨까요.? 그리고 서버쪽에 접속하는데 만약 서버가 여러대 라면 이런 방법도 괜찮을것 같습니다.

1. 프락시에서 서버쪽 타임 아웃은 5초(저는 보통 접속 타임아웃을 3초로 해놓았는데 어떤 경우에는 정상인데도 3초 이내에 접속이 안되는 경우가 왕왕 생기드라구요. 현재는 5초인데 이정도면 무사 통과 하는것 같습니다. 접속하는 서버의 갯수는 약 20개 정도이고 프로그램은 5가지 정도 됩니다.)

2. 서버는 5대가 존재.

3. 클라이언트는 접속 타임아웃이 21초

이럴 경우 클라이언트에서 최초 프락시에 접속한후에(이때도 타임아웃이 유효하겠죠) 프락시는 각 서버에 접속을 시도합니다. 5초 이내에 접속이 실패하면 다음 서버로 그리고 다음 서버로.. 그래서 최후 5대 모두 실패하면 클라이언트에게 메시지를 보내줍니다. 그리고 접속을 강제 종료합니다.

이럴 경우 클라이언트가 접속을 종료하는게 아니라 프락시에 접속을 종료 하는것이죠. 클라이언트는 아직 타임아웃이 1초 남아 있기 때문에 기다리는 상황인데 이때 서버쪽에 메시지를 받고(유효한 서버가 없습니다. 어쩌구..) 접속이 해지되는 상황입니다.

이런것은 어떨까요.? 원하시는것을 한번 더 포스팅 해주세요.

즐거운 하루 되세요.

shkwon81의 이미지

적절한 서버가 없다..

port unreachable, network unreachable 등의 예를 말씀하시는 듯 하군요..

예를 들면, 어떤 서버에 도달했는데 포트가 열려 있지 않다던지, 그런 IP로 도달할 수 없다든지요..

저런 처리는 ICMP라는 프로토콜을 통해 이루어집니다. 더 정확히 말하면, ICMP error message들이 처리합니다. 절대 TCP, UDP 자체가 저런 기능을 모두 처리하지는 않습니다.

따라서, 조금 고생할 맘만 있으시다면,(또 꼭 그렇게 하고 싶다면) ICMP를 분석해 보시기 바랍니다.

ICMP 규격에 맞도록 해당 서버에서 포트가 열려 있지 않은 경우, 프록시에서 에러에 해당하는 ICMP 패킷을 만들어서 이를 클라이언트로 보내주면 되겠지요.

ICMP 패킷 만들어 보낼 때는 raw socket을 사용하시면 되구요 ^^

그럼!

errai의 이미지

connection refuse는 해당하는 서버에서 접속을 거부했을 경우에
발생할 수 있는 상황입니다. 즉 어떤 서버로 접속을 시도했을때
서버에서 RST flag가 설정된 패킷을 클라이언트로 전송했을 경우에
클라이언트는 바로 접속을 끊게 됩니다.

port unreachable이나 network unreachable은 패킷이 전혀
그쪽 서버로 도달 할 수 없는 상황 (케이블이 연결되어 있지 않다든지)
에서 발생하므로 적절하지 않은것 같습니다.

하지만 위에서 논의 되었다 시피 강제적으로 서버에서 접속을 끊게
하는것보다는 서버로 연결을 실패했다는 메시지를 클라이언트로 전송하여
클라이언트에서 스스로 소켓을 close 시키는것이 더 좋은 방법이라고
생각합니다.

펑키의 이미지

잠깐 짬이 나서요...

하지만 위에서 논의 되었다 시피 강제적으로 서버에서 접속을 끊게 
하는것보다는 서버로 연결을 실패했다는 메시지를 클라이언트로 전송하여 
클라이언트에서 스스로 소켓을 close 시키는것이 더 좋은 방법이라고 
생각합니다.

이런 방법은 어떨까요.? 이벤트의 발생 위치를 생각해보면 클라이언트쪽이니 클라이언트가 접속을 끊겠 하는것이 일반적일것입니다. 그런데 클라이언트가 직접 제작하시는것이 아니라 telnet이나 혹은 http이실수도 있으시니 이럴때는 프락시쪽에서 강제로 접속을 끊어주시는게 어떨까요.? 그것이 아니라 클라이언트도 직접 제작하시는거라면 클라이언트에서 그러한 상황에서 접속을 끊게 하는것이 일반적이실겁니다.

그 반대로 클라이언트쪽에서 접속 해제시 서버쪽 접속을 해제하는것도 마찬가지 일것 같습니다. 또 이런 생각도 해볼수 있을것 같습니다. 그 중계 서버라는것이 만약 async 통신을 지원한다면.. 하는 경우입니다. 이럴 경우에는 이벤트가 발생하는 위치 자체가 별 의미가 없으므로 몇가지 룰을 정의 하셔서 하시면 될것 같습니다. 꼭!! 이렇게 해야 하는것은 절대 아닙니다. 그냥 제가 그런 방식으로 사용하고 있거든요.

낙엽의 이미지

쿨럭. -_- proxy open source도 있었군요. -_-

괜히 이리저리 건드려 봤네요.

혹시 참고가 되실듯 하면 open source로 있는 것보다는 소스양이 작으니까

필요하시다면 메일 주세요. ^^;

shkwon81의 이미지

Quote:
connection refuse는 해당하는 서버에서 접속을 거부했을 경우에
발생할 수 있는 상황입니다. 즉 어떤 서버로 접속을 시도했을때
서버에서 RST flag가 설정된 패킷을 클라이언트로 전송했을 경우에
클라이언트는 바로 접속을 끊게 됩니다.

확실히 그렇네요.. 제가 어먼 답변을 해 버렸습니다.
일반적으로 ICMP unreachable error는 중간 라우터에서 전송하는 게 맞습니다.

단, port unreachable error는 end host에서 전송하는 게 맞습니다. 그렇지만 TCP의 경우는 설명해 주신 것처럼 RESET을 이용하여 커넥션을 종료하구요.. UDP의 경우 열려진 포트가 없으면 ICMP port unreachable error를 전송합니다.

흠.. 제대로 확인해 보지 않고 어먼 답변을 해서 혼동하신 분들께 죄송 ㅠㅠ

mon12key의 이미지

리플 다신 분들 모두 감사하고요.

우선 client는 기존 툴을 사용하는 거라 client쪽으로 메세지를
보내 close()시키는 방법은 안되네요.

저는 우선 listen()하는 소켓을 close() 시킨뒤에 다시 열었는데,
client쪽 연결이 끊기지 않고, 다시 연결 시도 하더라구요. ^^;; 멀 잘못했는지

그래서 accept()로 연결하고 바로 close()시키는 방법을 채택했습니다.

근데 아래와 같이 client 쪽에 RST 패킷을 보내면 참 좋을 것 같은데 방법을
찾아 봐야 할 것 같습니다. TCP 레벨이라.. 그런 api가 있을런지 ^^a

errai wrote:
서버에서 RST flag가 설정된 패킷을 클라이언트로 전송했을 경우에
클라이언트는 바로 접속을 끊게 됩니다.
errai의 이미지

위에 올려주신 분들 글속에 답이 이미 있습니다만 간단한 pseudo code를
작성해보겠습니다.

...
listen(socket, 5);

select(socket + 1, ... );

if (FD_ISSET(socket, 읽기가능?) || FD_ISSET(socket, 쓰기가능?))
{
    // 접속 요청이 왔으므로 서버에 접속하여 접속이 가능한지
    // 살펴봅니다.
    if (server ready! ) {
        accept socket 및 기타 등등 하고자 하는것들 
    } else if (server busy) {
        // close() 함수를 불렀을때 RST 패킷을 전송하도록 소켓옵션 설정
        ling.l_onoff = 1;
        ling.l_linger = 0;
        setsockopt(socket, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling);
        close(socket); // 여기서 클라이언트로 RST 패킷 전송.
        // 종료 루틴.
    }
}

이런식으로 작성하면 클라이언트에서는 connect 시도를 했을때
바로 에러를 리턴하게 되므로 신경쓸 필요가 없습니다.

댓글 달기

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