본문 바로가기
💻 programming

[TCP/IP] 2. TCP 서버 - 클라이언트 (IPv4)

by 연구원-A 2020. 12. 18.
반응형

www.geeksforgeeks.org/socket-programming-cc/

 

Socket Programming in C/C++ - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

소켓 API를 사용하여 서버와 클라이언트의 통신을 수행하기 위해서는 클라이언트와 서버의 구분이 필요합니다. 서버와 클라이언트가 사용하는 API와 수행 단계가 각각 다르기 때문입니다. 여기서는 예제를 통해 클라이언트와 서버의 API 호출 순서를 설명하려고 합니다.

IPv4 TCP 클라이언트

1. socket( ): TCP 소켓 생성

int sockfd = socket(domain, type, protocol)
// Ipv4 protocol, tcp
// sock = socket(AF_INET, SOCK_STREAM, 0
  • sockfd: 소켓 식별자 (socket descriptor), integer를 반환합니다. 호출이 실패하면 -1의 값을 반한합니다
  • domain: integer, 통신 도메인 (e.g., AF_INET (IPv4), AF_INET6 (IPv6))
  • type: 통신 타입
    • SOCK_STREAM: TCP
    • SOCK_DGRAM: UDP
  • protocol: IP에 사용되는 프로토콜 값으로 0을 할당

2. connect( ): 서버와 연결 설정

socket( ) 함수를 이용해 생성한 소켓 식별자와 서버의 주소를 담고 있는 sockaddr을 전달하여 서버의 주소와 포트가 가리키는 서버 소켓에 연결을 시도합니다.

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

 

  • sockfd: 클라이언트에서 생성된 소켓
  • sockaddr: 서버의 주소를 담고 있는 sockaddr 구조체
  • addrlen: sockaddr 구조체의 실제 크기

3. send( ) 또는 recv( ): 데이터 송수신

TCP을 이용해서 recv( )를 호출할 때에는 매우 유의해야 합니다

stackoverflow.com/questions/666601/what-is-the-correct-way-of-reading-from-a-tcp-socket-in-c-c

 

What is the correct way of reading from a TCP socket in C/C++?

Here's my code: // Not all headers are relevant to the code snippet. #include #include #include #include #include <...

stackoverflow.com

📢  TCP는 바이트 스트림 (byte stream) 프로토콜이므로, UDP와 달리 데이터의 경계가 정해져있지 않습니다. 한 소켓에서 send( )를 한 번 호출하여 데이터를 전송하더라도 다른 소켓에서는 recv( )를 두 번 호출해야 데이터를 모두 수신하게 될 수도 있습니다. 추후 해당 내용에 대해 더 자세히 다루겠지만 모든 데이터를 수신하려면 보낸 데이터의 크기를 확인해서 정확한 바이트 수만큼 수신할 때까지 recv( )함수를 반복해야 합니다.

  • socket: recv( )를 호출할 소켓 기술자
  • x: 수신해야 하는 데이터의 크기
  • buffer: 수신할 데이터를 저장할 버퍼 (e.g. char[])
// This assumes buffer is at least x bytes long,
// and that the socket is blocking.
void ReadXBytes(int socket, unsigned int x, void* buffer)
{
    int bytesRead = 0;
    int result;
    while (bytesRead < x)
    {
        result = read(socket, buffer + bytesRead, x - bytesRead);
        if (result < 1 )
        {
            // Throw your error.
        }

        bytesRead += result;
    }
}

4. close( ): 연결 종료

 

IPv4 클라이언트 예제 코드

// Client side C/C++ program to demonstrate Socket programming 
#include <stdio.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <string.h> 
#define PORT 8080 
   
int main(int argc, char const *argv[]) 
{ 
    int sock = 0, valread; 
    struct sockaddr_in serv_addr; 
    char *hello = "Hello from client"; 
    char buffer[1024] = {0}; 
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    { 
        printf("\n Socket creation error \n"); 
        return -1; 
    } 
   
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_port = htons(PORT); 
       
    // Convert IPv4 and IPv6 addresses from text to binary form 
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)  
    { 
        printf("\nInvalid address/ Address not supported \n"); 
        return -1; 
    } 
   
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) 
    { 
        printf("\nConnection Failed \n"); 
        return -1; 
    } 
    send(sock , hello , strlen(hello) , 0 ); 
    printf("Hello message sent\n"); 
    valread = read( sock , buffer, 1024); 
    printf("%s\n",buffer ); 
    return 0; 
} 

 

 


 

 

// Server side C/C++ program to demonstrate Socket programming 
#include <unistd.h> 
#include <stdio.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
#include <netinet/in.h> 
#include <string.h> 
#define PORT 8080 
int main(int argc, char const *argv[]) 
{ 
    int server_fd, new_socket, valread; 
    struct sockaddr_in address; 
    int opt = 1; 
    int addrlen = sizeof(address); 
    char buffer[1024] = {0}; 
    char *hello = "Hello from server"; 
       
    // Creating socket file descriptor 
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) 
    { 
        perror("socket failed"); 
        exit(EXIT_FAILURE); 
    } 
       
    // Forcefully attaching socket to the port 8080 
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, 
                                                  &opt, sizeof(opt))) 
    { 
        perror("setsockopt"); 
        exit(EXIT_FAILURE); 
    } 
    address.sin_family = AF_INET; 
    address.sin_addr.s_addr = INADDR_ANY; 
    address.sin_port = htons( PORT ); 
       
    // Forcefully attaching socket to the port 8080 
    if (bind(server_fd, (struct sockaddr *)&address,  
                                 sizeof(address))<0) 
    { 
        perror("bind failed"); 
        exit(EXIT_FAILURE); 
    } 
    if (listen(server_fd, 3) < 0) 
    { 
        perror("listen"); 
        exit(EXIT_FAILURE); 
    } 
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address,  
                       (socklen_t*)&addrlen))<0) 
    { 
        perror("accept"); 
        exit(EXIT_FAILURE); 
    } 
    valread = read( new_socket , buffer, 1024); 
    printf("%s\n",buffer ); 
    send(new_socket , hello , strlen(hello) , 0 ); 
    printf("Hello message sent\n"); 
    return 0; 
} 
반응형

댓글