서버에서는 socket() 함수로 소켓 디스크립털르 할당받은 후에 bind() -> listen() -> accept() 시스템 콜을 차례대로 호출해서 클라이언트와 연결을 맺을 수 있다.
반대로, 클라이언트에서는 대기중인 서버에 연결 요청을 함으로써 서버-클라이언트 간의 연결이 생성될 수 있는데, 여기에 사용되는 시스템콜이 connect() 시스템 콜이다.
클라이언트의 소켓 생성 및 주소 할당
클라이언트의 경우에도 서버와 소켓 통신을 하려면 소켓을 하나 생성해야 한다. 즉, socket() 함수를 통해서 변수 sock에 디스크립터 번호를 지정한다. 다음으로는 연결을 요청할 서버의 주소를 소켓에 할당한다. 이때, 서버와는 달리 클라이언트는 본인의 IP address와 port number를 따로 지정할 필요가 없는데, 이는 연결을 요청하는 시점에 커널이 모두 알아서 지정해주기 때문이다.
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1)
error_handling("socket() error");
다음 serv_addr 구조체에 서버의 IP address, port number, protocol을 정의한다. 다음의 경우에는 ip address와 port number를 모두 사용자에게 입력받기 때문에 argv 변수에서 가져오도록 작성한다.
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
serv_addr.sin_port=htons(atoi(argv[2]);
클라이언트의 연결 요청
이제 어느 서버에 연결 요청을 할지 결정한 상태이므로, 실제로 connect()함수를 이용해 연결을 요청한다. 이렇게 클라이언트에서 connect() 시스템 콜을 호출하면, listen() 혹은 accept()로 대기중인 서버에 연결이 요청되며, 서버는 accept() 함수를 정상적으로 반환함으로써 두 호스트간에 연결이 성립된다. 즉, connect부터 accept까지 TCP 3way-handshake 과정이 성립된다.
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
error_handling("connect() error");
- sockfd : socket의 디스크립터 번호
- *addr : 연결을 요청할 서버의 구조체 주소
- addrlen : 서버 구조체 주소 변수의 길이
인용
'컴퓨터 사이언스 > Network' 카테고리의 다른 글
fork() 시스템 콜 (1) | 2023.11.21 |
---|---|
stream socket vs datagram socket (0) | 2023.11.21 |
서버의 시스템 콜(bind, listen, accept) (0) | 2023.11.21 |
HTTP version별 특징 (0) | 2023.11.21 |
proxy 서버 만들기 (0) | 2023.11.21 |