티스토리 뷰
* 본 포스팅은 한국소프트웨어진흥원 출처의 리눅스 네트워크 프로그래밍 PDF 파일을 토대로 작성되었습니다.
* 개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있음을 밝힙니다.
이번에는 TCP를 사용한 간단한 서버 프로그램을 만들어 보겠습니다.
서버 쪽에서는 포트번호를 arg로 입력받고 서버를 열고
클라이언트는 서버에 붙어 메시지를 입력하면 입력한 메시지를 다시 돌려받는
에코 서비스 서버입니다.
echo_server.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #include "stdio.h" #include "stdlib.h" #include "string.h" #include "time.h" #include "sys/types.h" #include "sys/socket.h" #include "netinet/in.h" //소켓 프로그래밍에 사용될 헤더파일 선언 #define BUF_LEN 128 //메시지 송수신에 사용될 버퍼 크기를 선언 int main(int argc, char *argv[]) { char buffer[BUF_LEN]; struct sockaddr_in server_addr, client_addr; char temp[20]; int server_fd, client_fd; //server_fd, client_fd : 각 소켓 번호 int len, msg_size; if(argc != 2) { printf("usage : %s [port]\n", argv[0]); exit(0); } if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {// 소켓 생성 printf("Server : Can't open stream socket\n"); exit(0); } memset(&server_addr, 0x00, sizeof(server_addr)); //server_Addr 을 NULL로 초기화 server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(atoi(argv[1])); //server_addr 셋팅 if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) <0) {//bind() 호출 printf("Server : Can't bind local address.\n"); exit(0); } if(listen(server_fd, 5) < 0) {//소켓을 수동 대기모드로 설정 printf("Server : Can't listening connect.\n"); exit(0); } memset(buffer, 0x00, sizeof(buffer)); printf("Server : wating connection request.\n"); len = sizeof(client_addr); while(1) { client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &len); if(client_fd < 0) { printf("Server: accept failed.\n"); exit(0); } inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, temp, sizeof(temp)); printf("Server : %s client connected.\n", temp); msg_size = read(client_fd, buffer, 1024); write(client_fd, buffer, msg_size); close(client_fd); printf("Server : %s client closed.\n", temp); } close(server_fd); return 0; } |
22~26 line : 서버 프로그램을 실행할 때 포트번호를 입력하지 않으면 프로그램이 종료됩니다.
28~32 line : socket 함수를 사용하여 서버측의 소켓을 생성합니다.
36~49 line : 서버측의 정보를 server_addr 구조체에 입력받습니다.
41~45 line : 생성한 소켓과 외부의 소켓주소를 묶어주는 bind 함수입니다.
47~51 line : 서버가 listen 함수를 통해 대기상태로 진입합니다. 최대 대기 클라이언트의 수는 5입니다.
58~63 line : 클라이언트의 요청을 감지하면 accept 함수가 실행되고 그 반환 값으로 클라이언트의 소켓번호가 생성됩니다.
64 line : 접속한 클라이언트의 IP를 확인하기 위해 inet_ntop 함수를 사용합니다.
67 line : 클라이언트가 값을 입력하는 값을 받기 위한 read 함수입니다.
68 line : 클라이언트로 부터 입력받은 값을 다시 write 합니다.
69 line : 클라이언트의 소켓을 닫습니다.
72 line : 서버의 소켓을 닫습니다.
실제로 컴파일하고 실행해보겠습니다.
gcc로 컴파일한 후 포트번호를 인자로 준 에코서버 프로그램을 실행하면
연결을 기다리고 있다는 문구가 뜹니다 (포트번호가 사용 중이거나 등등의 이유로 bind 에러가 발생할 수 있습니다)
다른 쉘을 띄워서 로컬호스트(127.0.0.1)로 접속해 보겠습니다
nc 명령어로 접속한 후 프롬프트에 특정 문구를 입력하면 똑같이 되돌아 오는 것을 확인 할 수 있습니다.
그리고 다시 서버로 돌아오면
위와 같이 접속한 클라이언트의 로그가 남는 것을 확인 할 수 있네요.
accept 부분에 무한루프(while)을 걸어놨기 때문에 Ctrl+c 를 통해 종료하지 않는 이상 서버 프로그램이 종료 되지 않기때문에
서버 프로그램만 돌아가고 있으면 계속해서 nc로 붙을 수가 있습니다.
'개인공부 > 소켓 프로그래밍' 카테고리의 다른 글
리눅스 소켓 프로그래밍 08 : TCP 서버 작성절차, 함수 (0) | 2014.02.11 |
---|---|
리눅스 소켓 프로그래밍 07 : TCP 클라이언트 프로그램 예제 (0) | 2014.02.08 |
리눅스 소켓 프로그래밍 06 : TCP 클라이언트 작성절차, 함수 (0) | 2014.02.07 |
리눅스 소켓 프로그래밍 05 : IP, 도메인 주소변환 (3) | 2014.02.03 |
리눅스 소켓 프로그래밍 04 : 소켓주소 구조체 (0) | 2014.02.02 |
리눅스 소켓 프로그래밍 03 : 디스크립터 확인 예제 (2) | 2014.02.02 |
리눅스 소켓 프로그래밍 02 : 소켓 socket() 함수 (3) | 2014.02.02 |