TCP 프로토콜을 이용산 소켓 프로그래밍, udpecho_server/client
- TCP 프로토콜을 이용산 소켓 프로그래밍
server |
clinet |
서버에 소켓 생성(client와 연결을 위해 필요한 소켓) - socket() 서버에 주소 할당 - bind() 연결 요청 대기모드로 설정 - listen() 클라이언트 연결 요청시 새로운 소켓 생성 - accept() 송(write(), send()) / 수신(read(), recv()) 클라이언트 소켓 닫기 - close() |
소켓 생성 - socket()
연결 요청(접속할 서버의 IP, PORT) - connect() 송(write(), send()) / 수신(read(), recv()) 소켓 닫기 - close() |
⇒ TCP → 연결형 프로토콜(전화와 비슷)
→ 두 시스템 간 연결이 성공한 후에 데이터 전송 시작함
(3-way handshaking)
→ 연결 요청이 왔을 때 위와 같이 3번 이동하며 연결한다.
1) 송신 호스트가 SYN Flag값을 1로 설정한 TCP packet과 임의의 Sequence Number를 수신 호스트로 보낸다. Ex) 송신 --------------------------> 수신 SYN=1, SEQ=J 2) 수신 호스트가 Session성립을 원하면 SYN Flag를 1로 설정하고 ACK를 송신 호스트가 보낸 SEQ번호의 다음 번호로 정하고 수신 호스트에 따로 설정한 SEQ번호를 보낸다. Ex) 송신 <-------------------------- 수신 SYN=1, ACK=J+1, SEQ=K 3) 송신 호스트는 ACK 값을 수신지 호스트가 보낸 SEQ번호의 다음 번호로 정하여 수신 호스트에 보낸다. Ex) 송신 --------------------------> 수신 ACK=K+1 |
→ 신뢰성 보장(순차적 데이터 전달, 데이터 재전송)
→ 데이터 경계를 구분하지 않는다.
⇒ UDP → 비연결형 프로토콜(편지와 비슷)
→ 연결 없이 통신 가능
→ 비신뢰적인 데이터 전송(전송순서에 상관없이 가장 빠른 전송 지향, 전송도중 데이터가 손실되어도 재전송 되지 않음.)
→ 데이터의 경계를 구분함(Datagram 서비스)
⇒ 연결형 서버 → TCP 프로토콜을 이용, TCP 소켓을 사용한다.
비연결형 서버 → UDP 소켓 사용. (연결 요청을 하지 않는다.)
⇒ iterative server → 순서대로 client와 송/수신
→ client와 서비스 시간이 짧은 경우에 사용한다.
concurrent server → server와 client 서비스 시간이 불균형 적일 때 사용한다.
⇒ client 연결 요청 간 새로운 소켓 생성(accept())부터 client 소켓 닫기(close()) 까지를 반복시키면 iterative server가 된다.
// helloworld_iterative_server.c에서 연결 요청 수락 부분에 반복문 사용을 통한 iterative server 만들기
// 소켓에 주소 할당
if( bind(serv_sock, (struct sockaddr*)& serv_addr, sizeof(serv_addr)) == -1)
{
error_handling("bind() error");
}
// 연결 요청 대기상태로 진입
if(listen(serv_sock, 5) == -1)
{
error_handling("listen() error");
}
// 연결 요청 수락
clnt_addr_size = sizeof(clnt_addr);
for(;;) // iterative 서버를 만들기 위해 반복한다.
{
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// IP주소, INADDR_ANY - 사용중인 ip의 주소를 자동으로 찾아준다.
// htonl() - little endian 방식을 big endian 방식으로 바꾸어 준다.
printf("%s\n", inet_ntoa(clnt_addr.sin_addr)); // IP 주소 출력
printf("%d\n", ntohs(clnt_addr.sin_port)); // PORT 번호 출력
if(clnt_sock == -1)
{
error_handling("accept() error");
}
// 데이터 전송
write(clnt_sock, message, sizeof(message));
sleep(5);
// 연결 종료
close(clnt_sock);
}
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
⇒ iterative server 만들기에서 client 소켓 닫기를 하지 않으면 생성된 소켓이 계속 남아있게 된다.
⇒ write() / read() 는 send() / recv()로 바꾸어 사용할 수 있다. 단, linux에서만 가능.
⇒ send()와 recv()에 대해 살펴보면(man 2 send 명령으로도 찾을 수 있다.)
→ send() 호출의 선언은 아래와 같다.
int send(int sockfd, const void *msg, int len, int flags);
→ sockfd는 socket()를 통해서 얻었거나 accept()를 통해서 새로 구한, 데이터를 보낼 소켓의 기술자, msg는 보낼 데이터를 가리키는 포인터, len은 보낼 데이터의 바이트 수, flags는 대부분의 경우 0으로 해야 한다.
→ recv() 호출의 선언은 아래와 같다.
int recv(int sockfd, void *buf, int len, unsigned int flags);
→ sockfd는 읽어올 소켓의 기술자이며 buf는 정보를 담을 버퍼. len은 버퍼의 최대 크기, flags는 대부분의 경우 0으로 세팅해야 한다.
⇒ write(clnt_sock, message, sizeof(message));
→ send(cnt_sock, message, sizeof(message), 0); 으로 바꾸어 쓸 수 있다.
- udpecho_server/ udpecho_client 테스트
'내장형 하드웨어 > TCP/IP' 카테고리의 다른 글
네트워크 - 시리얼 통신(멀티플렉스) (0) | 2011.10.27 |
---|---|
네트워크 - 인터럽트(interrupt) -> sigaction() (0) | 2011.10.26 |
네트워크 - Server, Client간 다중 접속(채팅) (0) | 2011.10.24 |
네트워크 - TCP 통신 (Client, Server) / 다중 Client 접속 (4) | 2011.10.21 |
TCP/IP - fork_test.c, 좀비 프로세스 (0) | 2011.07.14 |