Showing posts with label socket. Show all posts
Showing posts with label socket. Show all posts

Friday, June 20, 2008

TCP Status

TCP연결시에는 알다시피 3way handshaking을 한다. close시에는 client, server 가 각각 FIN을 보낸 후 ACK를 받는다(총 4번의 트랜젝션).

TCP연결에는 여러개의 상태가 있는데, netstat으로 확인할 수 있는 상태들에 대해 간단히 정리해보면,

  • 서버에서 listen()이 호출되면 상태는 LISTEN으로 바뀐다.

  • 이 때 client에서 SYN을 보낸 후 SYN_SENT로 상태가 바뀌면

  • 서버에서 이를 받고 SYN_RCVD로 바뀌고 SYN ACK를 보내준다.

  • 그리고 client에서 SYN을 다시 받게 되면 비로소 ESTABLISHED로 바뀐다.

  • 이 후 send(), recv()군의 함수들로 계속 통신을 하다가

  • client에서 close()호출로 인해 FIN 을 보내고 FIN_WAIT1상태가 되면

  • 서버에서 이를 받고 ACK를 보낸 후 CLOSE_WAIT으로 상태를 바꾸고

  • client에서는 이를 받으면 FIN_WAIT2로 바뀌게 된다.

  • client에서 close할 준비가 끝났으므로, 이제는 서버에서 close()가 호출되면 FIN이 전송되고, 상태는 LAST_ACK이 된다.

  • client에서는 ACK를 보낸 후 TIME_WAIT상태가 되고, Maximum Segment Lifetime x 2시간 정도 기다리다가 소켓을 닫는다.

  • 서버에서는 이 ACK를 받고 CLOSED로 상태가 바뀐다.


close시 일반적으로 client에서 먼저 FIN을 보내고(active close), 서버는 이를 받으면 recv()에 EOF가 전달된다. 서버는 자신이 보낸 FIN에 대한 ACK를 받아야 close된다(passive close).

TIME_WAIT이 필요한 이유 client에서 ACK를 보냈는데, 서버가 못받으면, 서버는 LAST_ACK상태에서 일정시간이 지나도 ACK가 안오므로 FIN을 다시 보낸다. 이때 client가 이미 close 한 상태이거나 같은 포트번호로 다른 접속을 시도하고 있다면 처리할 수 없으니까, TIME_WAIT을 두어 다시 들어온 FIN에 대해 ACK를 주는 것이다. (client에서는 그래서 재접속시 다른 포트 번호를 받게 된다).

Thursday, June 5, 2008

Socket, getsockname

이미 binding 된 socket으로 부터 주소정보를 받아올 때 getsockname을 사용한다. 아래와 같이 사용하면 된다.

getsockname(sfd, (struct sockaddr *)&saddr, &len_saddr);

Wednesday, June 4, 2008

Socket, thundering herd problem

network 프로그래밍시 주의해야할 문제 중에 하나로 thundering herd problem이 있다. 천둥이 치면 소떼가 뛴다...는 상황을 비교해서 쓰는 말인데, 여러 thread/process 간에 공유된 자원이 있을 때 자원이 사용가능하게 되지마자 block되어 있던 모든 프로세스들이 깨어나지만 한 프로세스만 자원을 점유하고 나머지는 다시 block되어야 하므로 CPU time을 낭비하게 된다. Mutex 같은 lock을 통해 이런 문제를 해결할 수 있다고 하는데,.. 그런가 ㅡ.ㅡ;,..

Monday, June 2, 2008

Socket, code example

간단히 ... 잊지 않을 정도의 코드 예제를 적어본다.
server side

#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

int sfd, rsfd;
struct sockaddr saddr; // listener
struct sockaddr rsaddr;

sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

saddr.sin_family = AF_INET;
saddr.sin_port = 10000;
saddr.sin_addr.s_addr = inet_addr("100.100.100.100");
// or inet_aton

bind(sfd, (struct sockaddr*)&saddr, sizeof(saddr));

listen(sfd, BACKLOG);

rsfd = accept(sfd, (struct sockaddr *)&saddr, &len_rsaddr);

recv(rsfd, rbuf, sizeof(rbuf), 0);

send(rsfd, sbuf, sizeof(sbuf), 0);

shutdown(rsfd, SHUT_RDWR); // or close

client side

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int sfd;
struct sockaddr saddr;

sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

saddr.sin_family = AF_INET;
saddr.sin_port = 10000;
inet_aton("100.100.100.100", &saddr.sin_addr);
// or inet_addr

connect(sfd, (struct sockaddr*)saddr, sizeof(saddr));

send(sfd, sbuf, sizeof(sbuf), 0);

recv(sfd, rbuf, sizeof(rbuf), 0);

close(sfd); // or shutdown