Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
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
Archives
Today
Total
관리 메뉴

codingfarm

4. 소켓 네트워크 프로그램 개발 - 9, 10. 소켓 프로그램(linux) 본문

TCP IP 소켓 프로그래밍

4. 소켓 네트워크 프로그램 개발 - 9, 10. 소켓 프로그램(linux)

scarecrow1992 2021. 5. 11. 23:36

이제 리눅스 환경에서의 소켓 클라이언트 프로그램을 작성해본다

클라이언트가 보낸 문자열을 서버에서 받아, 고스란히 되돌려주는 에코 프로그램을 작성해보자

포트번호는 3500으로 할것이다. 컴퓨터가 두대라면 효율적인 실습 가능하겠지만, 사정상 한대의 컴퓨터만 준비 가능하다면 루프백 주소인 '127.0.0.1'로 테스트 해본다.

여기서는 2개의 가상 OS를 이용하여 각각 client와 server의 역할을 수행하도록 한다.

 

좌측이 client로 쓸 OS, 우측이 server로 쓸 OS로

각각의 IP가

192.168.175.131

192.168.175.132

인것을 확인했다.

 

클라이언트 프로그램

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
#include <sys/socket.h> /* 소켓 관련 함수 */
#include <arpa/inet.h>  /* 소켓 지원을 위한 각종 함수 */
#include <sys/stat.h>
#include <stdio.h>      /* 표준 입출력 관련 */
#include <string.h>     /* 문자열 관련 */
#include <unistd.h>     /* 각종 시스템 함수 */
 
#define MAXLINE     1024
 
int main(int argc, char **argv){
    struct sockaddr_in serveraddr;
    int server_sockfd;
    int client_len;
    char buf[MAXLINE];
 
    if((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("error :");
        return 1;
    }
 
    /* 연결 요청할 서버의 주소와 포트 번호 프로토콜 등을 지정한다. */
 
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr("192.168.175.132");
    serveraddr.sin_port = htons(atoi(argv[1]));
 
    client_len = sizeof(serveraddr);
 
    /* 서버에 연결을 시도한다. */
    if (connect(server_sockfd, (struct sockaddr *)&serveraddr, client_len) == -1){
        perror("connect error : ");
        return 1;
    }
 
    memset(buf, 0x00, MAXLINE);
    read(0, buf, MAXLINE);  // 키보드 입력을 기다린다.
    if(write(server_sockfd, buf, MAXLINE) <= 0){
        perror("write error : ");
        return 1;
    }
 
    memset(buf, 0x00, MAXLINE);
    /* 서버로부터 데이터를 읽는다. */
    if(read(server_sockfd, buf, MAXLINE) <= 0){
        perror("read error : ");
        return 1;
    }
 
    close(server_sockfd);
    printf("read : %s", buf);
    return 0;
}
cs

 

 

 

서버 프로그램

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
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define MAXBUF 1024 /* 클라이언트와 길이를 맞춘다 */
int main(int argc, char **argv){
    int server_sockfd, client_sockfd;
    int client_len, n;
    char buf[MAXBUF];
    struct sockaddr_in clientaddr, serveraddr;
 
    client_len = sizeof(clientaddr);
 
    if((server_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1){
        perror("socket error : ");
        exit(0);
    }
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(atoi(argv[1]));
 
    bind(server_sockfd, (struct sockaddr *&serveraddr, sizeof(serveraddr));
    listen(server_sockfd, 5);
 
    while(1){
        memset(buf, 0x00, MAXBUF);
        client_sockfd = accept(server_sockfd, (struct sockaddr *&clientaddr, &client_len);
        printf("New client connect: %s\n", inet_ntoa(clientaddr.sin_addr));
 
        if((n = read(client_sockfd, buf, MAXBUF)) <= 0){
            close(client_sockfd);
            continue;
        }
        if(write(client_sockfd, buf, MAXBUF) <= 0){
            perror("write error : ");
            close(client_sockfd);
        }
        close(client_sockfd);
    }
    close(server_sockfd);
    return 0;
}
cs

 

 

 

2개의 코드를 별개의 가상 OS에서 컴파일 한 후, main의 매개변수로 포트번호를 전달하고 연결을 시도해본다.

각 클라이언트와 서버의 프로그램 이름이 echo_client, echo_server 이며, 아래처럼 실행해보면

 

echo_client

 

echo_server

 

client를 실행한 후 타이핑한 문자열이 서버에 전송되었다가 클라이언트에서 다시 받아 무사히 문자열을 출력하는것을 확인하였다.

반드시 server를 먼저 실행하고 client도 실행해야한다.

 

하지만 위 프로그램은 단점이 있는데

server측에서는 무한루프를 통해 client를 받고 있으며 별도의 탈출 분기점이 없다.

그렇기에 강제 종료를 시켜야하는데 그에 따라 서버측의 듣기 소켓을 close 할 수 없게 된다.

그에 따라 server 시스템에서는 해당 포트를 점유중인 소켓이 계속 살아있는 상태이므로, 포트를 사용할 수 없게 된다.

 

 

Comments