[질문] 소켓에서 Connect 가 성공하는 시점이 어떻게 되나요?

ulsiguya의 이미지

소켓 프로그래밍을 하고 있습니다. TCP를 이용하는데요...

서버가 클라이언트 한 채널을 접속 받은 후에 더이상 Listen을 하지 않고 접속된 채널만 가지고 데이터를 날릴려구 합니다. 다시 말해서

서버 Listen -> 클라이언트 connect -> 서버 accept -> 서버 Lisetn 소켓 닫음 -> 데이터 통신 -> 서버, 클라이언트 소켓 닫음.

그런데, 제가 질문을 드리는 것은요...

서버가 Listen을 할때 문제입니다. 서버가 Listen을 하고 있는 상태에서 클라이언트로 부터 connect가 들어왔을때 select 함수가 풀리면서 accept를 하게 했습니다.

그런데, 동작을 시켜보니, 클라이언트는 connect가 성공을 했다고 하는데, 실질적으로는 서버가 아직 한채널도 붙지 않았고, listen상태이라는 겁니다. 다시 말해서 accept 함수가 호출된적이 없는데, 클라이언트는 connect가 되서 마냥 좋다고 데이터가 오기를 기다리고 있는 거죠...

제가 알기로는 서버가 accept를 해줘야, 클라이언트의 connect 함수가 풀리는 것으로 알고 있는데요... (블럭킹 모드 입니다...)

뭐가 문제가 있는 걸까요? 혹시 경험하신분 있으시면...

참고로, 서버를 다시 실행시키면 잘 됩니다. 그러다가 한 1000번 정도 접속을 하고 나면 하나 둘씩 위와 같은 문제가 발생됩니다.... 그리고 한꺼번에 접속이 200개 정도가 들어올수도 있습니다. 그러니깐, 200 포트가 동시에 listen상태로 있다가 접속되면 사라지는 것이겠죠.... 아, 그리고 서버는 리눅스고 클라이언트는 윈도우 입니다.

부탁합니다....

File attachments: 
첨부파일 크기
Image icon xx.GIF16.19 KB
yeppiguy의 이미지

listen소켓을 왜 닫죠?
ulsiguya님께서 말씀하시는 걸로 봐서는 여러개의 클라이언트를 처리하는 거라면, 굳이 listen소켓을 닫을 필요가 없을텐데요.

문제가 되지 않는다면, 소스를 올려놓으시면, 좀 더 답변이 명확해 질거 같네요.

ulsiguya의 이미지

음... listen 하는 소켓은 마냥 커넥션을 기다리는 것이 아니라, 한 커넥션만 받고 닫아 버리는 거라서 그렇습니다. 다시 말해서 서버가 한 포트를 열고 기다리는 형태의 것이 아니구요... 데이터 전송을 위해 TCP 연결이 필요해서 그렇게 사용한것입니다. 그리고 listen 소켓 포트 번호는 계속적으로 변하고요...

pynoos의 이미지

port manager 같은 것을 구현하였나보군요.

connection은 accept가 되는 시점에 return 되는 것이 아니라, listen하는 port라면 OS는 connect 되었다고 바로 알려주고 listen의 back log queue에 대기시켜놓게됩니다.

그런상황이 발생하게 되면, lsof 를 사용하여 실제 어떤 process가 listen socket을 잡고 있는지 확인해보시기 바랍니다.

rasungboy의 이미지

의도하신게 하나의 커넥션만 받고 리슨소켓을 닫는거라면

리슨에서 여러개의 커넥션을 받아도 어셉트만 한번 호출하고

리슨소켓 닫아버리면 맨처음 커넥션걸린것만 처리하니

위도하신대로 되는게 아닐까 합니다..

아마 늦게 접속한 클라이언트에서는 커넥션성공이후 바로

접속종료이벤트가 발생할거구요..

익명 사용자의 이미지

서버에서 listen()이 되는 시점부터 클라이언트는 connect가 됩니다.
accept()를 하지 않더라도 클라이언트는 connect()가 성공이 되는거죠.

위 문제는
클라이언트가 connect()하고 데이터를 무한히 기다리는건
서버에서 select()에서 listen_socket_fd를 체크하지 않았을 경우에
해당되는 사항으로 여겨집니다.
서버에서 listen_socket_fd를 닫는 시점을,
select() 에서 체크하지 않는 시점을 잘 찾아보시면 될거라 여겨집니다.

이상 허접 대답이였습니다.

ulsiguya의 이미지

친절한 답변 감사합니다. 저도 accept가 되어야 connect함수가 풀리는줄 알았는데요... 그게 아니었군요...

select 쪽을 다시 봐야겠습니다... ^^;

익명 사용자의 이미지

Quote:
저도 accept가 되어야 connect함수가 풀리는줄 알았는데요... 그게 아니었군요...

그게 아니고가 아닙니다.

그림 참고하세요.

댓글 첨부 파일: 
첨부파일 크기
Image icon 0바이트
익명 사용자의 이미지

위그림의 부연입니다.
위 그림에서 클라이언트가 ACK 패킷을 보냈는데,
중간에 뭔가(많은 문제가 있을 수 있습니다) 문제가 발생해서, 서버는 무한하게(사실은 타임아웃있지요) 대기중인것으로 보입니다.
클라이언트 connect 이미 SYN|ACK받았고, ACK보냈으니, 할 일 다해서 리턴한 상황일테고 모 이렇게 보입니다.

익명 사용자의 이미지

Anonymous wrote:
위그림의 부연입니다.
위 그림에서 클라이언트가 ACK 패킷을 보냈는데,
중간에 뭔가(많은 문제가 있을 수 있습니다) 문제가 발생해서, 서버는 무한하게(사실은 타임아웃있지요) 대기중인것으로 보입니다.
클라이언트 connect 이미 SYN|ACK받았고, ACK보냈으니, 할 일 다해서 리턴한 상황일테고 모 이렇게 보입니다.

따라서, 클라이언트는 연결된것으로 인지하며, 서버는 아직 클라이언트로 부터 3 way handshake의 최종응답인 ACK를 받지 못하여 연결 안된것으로 인지합니다.
즉, 비동기지요 TCP/IP는요.
익명 사용자의 이미지

위에 손님 그림 틀렸습니다.

그림에서 서버가 SYN을 받는 시점이 accept()를 부른 후라고 되어 있는데 이건 전혀 사실이 아닙니다. 몇줄 짜서 돌려보세요.

listen()을 한다는게 os한테 이제 부터 이 포트(정확히는 특정 interface를 지정할 수 도 있습니다만)로 오는건 정상적인 접속이니까 처리해주세요~ 라고 알리는 겁니다.

그래서 client가 connect()을 부르면 SYN이 서버로 오게되고 os는 이걸 받아서 SYN/ACK를 날리고 이제 이것은 접속중인 상태로 넘어오게 됩니다. client입장에서는 SYN/ACK를 받았으니 정상적인 접속이 이루어 진것으로 생각하고 ACK를 날리게 됩니다.

listen()에 두번째 인자인 backlog라는게 왜 있는지 생각해 보세요. SYN에 대해서 서버가 SYN/ACK를 날리고 나면 이는 backlog값(정확한 값이 아니고 platform마다 다릅니다)의 크기만큼은 queue로 들어가게 되고, 나머지는 SYN에 대해서 대답을 못 받거나 RST가 날아겠지요. accept()는 os한테 접속한 놈이 있으면 queue에서 하나 줘~ 라고 요청하는 겁니다.

ulsiguya의 이미지

위의 님들께서 말씀을 하시길레 플그램을 짜서 돌려봤습니다. 손님2의 말씀이 맞는 것 같더군요.... 의미도 맞는 것 같습니다....

하여간에, 주위에 많은 분들에게 물어본 결과 accept가 호출되어야만 connect가 풀리는 걸로 아시더군요... 사실 그렇지 않은데 말이죠.... 손님2의 말씀대로 accept는 OS한테 하나줘~ 라고 요청하는 거더군요....

marten의 이미지

손님2 wrote:
위에 손님 그림 틀렸습니다.

그림에서 서버가 SYN을 받는 시점이 accept()를 부른 후라고 되어 있는데 이건 전혀 사실이 아닙니다. 몇줄 짜서 돌려보세요.

그림 자체가 틀렸다고 볼 수는 없을 듯 합니다.
그림에서 서버는 listen()을 호출한 후, 곧바로 accept() 를 블럭킹 모드로 호출했군요. 그렇다면, 클라이언트의 SYN 패킷이 accept() 호출 이후에 도착할 수도 있을테지요. 그리고 accept()는 클라이언트의 ACK 패킷이 도착할 때까지 블럭되어 있을 것입니다.

Quote:

man accept

...

If no pending connections are present on the queue, and the socket is not marked as non-blocking, accept blocks the caller until a connection is present.

...

댓글 달기

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