๊ธ€ ์ž‘์„ฑ์ž: ๋˜ฅํด๋ฒ .
๋ฐ˜์‘ํ˜•

๋ชฉ์ฐจ


  • Socket Buffer? (Send Socket Buffer / Receive Socket Buffer)
  • Socket Buffer ์‚ฌ์ด์ฆˆ ๋ณ€๊ฒฝ, ์‚ฌ์ด์ฆˆ ํ™•์ธ, ๋ฒ„ํผ ๋ฐ์ดํ„ฐ ํ™•์ธ
  • Socket Buffer ๋™์ž‘ ํ…Œ์ŠคํŠธ

 

Socket Buffer? (Send Socket Buffer / Receive Socket Buffer)


[๊ทธ๋ฆผ 1] ๋ฐ์ดํ„ฐ ์ „์†ก ์‹œ TCP/IP ๋„คํŠธ์›Œํฌ ์Šคํƒ์˜ ๊ฐ ๋ ˆ์ด์–ด ๋ณ„ ๋™์ž‘ ๊ณผ์ •

์œ„์˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด TCP ํ†ต์‹ ์—์„œ Application์ด ๋ฉ”์‹œ์ง€๋ฅผ write๋ฅผ ํ•œ๋‹ค๊ณ  ๋ฐ”๋กœ ๋ฉ”์„ธ์ง€๊ฐ€ ์ „์†ก๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.

์†Œ์ผ“ ๋ฒ„ํผ(Send socket buffer)๋ผ๋Š” ๋ฒ„ํผ์— ์Œ“์ธ ํ›„ ์ ์ ˆํ•œ ์‹œ๊ธฐ์— ์ƒ๋Œ€๋ฐฉ์—๊ฒŒ ๋ฉ”์‹œ์ง€๊ฐ€ ์ „์†ก๋˜๊ณ  ๋ฒ„ํผ๊ฐ€ ์ง€์›Œ์ง„๋‹ค.

 

[๊ทธ๋ฆผ 2] ๋ฐ์ดํ„ฐ ์ˆ˜์‹  ์‹œ TCP/IP ๋„คํŠธ์›Œํฌ ์Šคํƒ์˜ ๊ฐ ๋ ˆ์ด์–ด ๋ณ„ ๋™์ž‘ ๊ณผ์ •

๋ฐ›๋Š” ์ชฝ์—์„œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฉ”์‹œ์ง€๊ฐ€ ์˜ค๋ฉด ์ผ๋‹จ, ์†Œ์ผ“ ๋ฒ„ํผ(Receive socket buffer)์— ์ €์žฅ ๋œ ํ›„ Application์—์„œ readํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ†ตํ•ด ์†Œ์ผ“ ๋ฒ„ํผ์— ์Œ“์ธ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์–ด ๋“ค์ธ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ผ ๋•Œ Send Socket Buffer๊ฐ€ ๊ฝ‰ ์ฐฌ ์ƒํƒœ๋ผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

 

[๊ทธ๋ฆผ 3] linux man ํŽ˜์ด์ง€ (https://linux.die.net/man/2/send)

 

๋ฆฌ๋ˆ…์Šค ๊ธฐ์ค€์œผ๋กœ, ์†Œ์ผ“์ด Blocking ๋ชจ๋“œ๋ผ๋ฉด Send Socket buffer๊ฐ€ ๋น„์›Œ์งˆ ๋•Œ๊นŒ์ง€ Block ๋˜๊ณ , NonBlocking ๋ชจ๋“œ๋ผ๋ฉด EAGAIN ํ˜น์€ EWOULDBLOCK์ด๋ผ๋Š” ์—๋Ÿฌ๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.

https://linux.die.net/man/2/send

 

Socket Buffer ์‚ฌ์ด์ฆˆ ๋ณ€๊ฒฝ, ์‚ฌ์ด์ฆˆ ํ™•์ธ, ๋ฒ„ํผ ๋ฐ์ดํ„ฐ ํ™•์ธ


 Socket Buffer์˜ ๊ธฐ๋ณธ ์‚ฌ์ด์ฆˆ๋Š” ๋ฆฌ๋ˆ…์Šค ๊ธฐ์ค€์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์žกํ˜€์žˆ๋‹ค.

/proc/sys/net/core/wmem_max // send buffer
/proc/sys/net/core/rmem_max // receive buffer

์œ„์™€ ๊ฐ™์€ ํŒŒ์ผ์„ ์ˆ˜์ •ํ•จ์œผ๋กœ์จ Socket Buffer์˜ ์‚ฌ์ด์ฆˆ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

 

ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ƒ์—์„œ ๊ฐ ์†Œ์ผ“๋งˆ๋‹ค Sockte Buffer ์‚ฌ์ด์ฆˆ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ํ™•์ธํ•˜๊ณ  ์‹ถ์œผ๋ฉด ์•„๋ž˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

#include <sys/types.h>
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

 

๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ๋ณด์ž.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>

int main() {
    int serverSocket;
    struct sockaddr_in serverAddr;

    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(serverSocket == -1)
    {
        exit(1);
    }

    int bufSize = 1024 * 4;
    socklen_t len = sizeof(bufSize);
    setsockopt(serverSocket, SOL_SOCKET, SO_SNDBUF, &bufSize, sizeof(bufSize));
    getsockopt(serverSocket, SOL_SOCKET, SO_SNDBUF, &bufSize, &len);
    printf("socket buffer size: %d\n", bufSize);
    
    close(serverSocket);
    return 0;
}
socket buffer size: 8192

๋ถ„๋ช…ํžˆ 1024 * 4 = 4,096์ด๋ผ๋Š” ํฌ๊ธฐ๋กœ Socket Buffer ์‚ฌ์ด์ฆˆ๋ฅผ ์„ค์ •ํ–ˆ๋Š”๋ฐ 8,192๋ผ๋Š” ๊ฐ’์ด ๋‚˜์™”๋‹ค.

๊ทธ ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

[๊ทธ๋ฆผ 4] linux man ํŽ˜์ด์ง€ (https://linux.die.net/man/7/tcp) 

ํ•ด์„ํ•˜์ž๋ฉด, ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์ด์ฆˆ๋ฅผ ๋ช…์‹œํ•ด์ค€ ๋Œ€๋กœ ๊ทธ๋Œ€๋กœ ์„ค์ •๋˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋‹ค.

์ปค๋„ ๋‚ด๋ถ€์—์„œ ๊ฐ’์„ 2๋ฐฐ ์‹œ์ผœ์ฃผ๊ฑฐ๋‚˜ ์ ๋‹นํ•œ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•ด์ค€๋‹ค๊ณ  ํ•œ๋‹ค.

 

 Socket Buffer์— ๋ฐ์ดํ„ฐ๋ฅผ write๋ฅผ ํ–ˆ์„ ๋•Œ Buffer์— ๋ฐ์ดํ„ฐ๊ฐ€ ์–ผ๋งˆ๋‚˜ ์žˆ๋Š”์ง€ ํ™•์ธ์€ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ํ• ๊นŒ?

#include <sys/ioctl.h>
int ioctl(int d, int request, ...);

์œ„์™€ ๊ฐ™์€ ํ•จ์ˆ˜๋กœ ์ ์ ˆํ•œ ์ธ์ž ๊ฐ’์„ ์ฃผ์–ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•œ๋‹ค. ๋‘ ๋ง ํ•„์š” ์—†์ด ๊ฐ„๋‹จํ•œ ์˜ˆ๋ฅผ ๋ณด์ž!

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>

int main() {
    int serverSocket;
    struct sockaddr_in serverAddr;

    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(serverSocket == -1)
    {
        exit(1);
    }
    int remainSize;
    ioctl(serverSocket, SIOCOUTQ, &remainSize);
    printf("remain data size: %d\n", remainSize);

    close(serverSocket);

    return 0;
}
remain data size: 0

 

Socket Buffer ๋™์ž‘ ํ…Œ์ŠคํŠธ


 ๋งˆ์ง€๋ง‰์œผ๋กœ Socket Buffer๊ฐ€ ์ œ๋Œ€๋กœ ๋™์ž‘ ํ•˜๋‚˜ ์„œ๋ฒ„ - ํด๋ผ์ด์–ธํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ํ…Œ์ŠคํŠธํ•ด๋ดค๋‹ค.

1. ์„œ๋ฒ„ ์†Œ์ผ“์„ ์ƒ์„ฑํ•œ ๋’ค bind - listen - accept ๊ณผ์ •์„ ๊ฑฐ์ณ ํด๋ผ์ด์–ธํŠธ์˜ ์ ‘์†์„ ๋ฐ›์Œ.

2. ์ ‘์†๋œ ํด๋ผ์ด์–ธํŠธ ์†Œ์ผ“์˜ send socket buffer ์‚ฌ์ด์ฆˆ๋ฅผ ๋ณ€๊ฒฝ

3. send socket buffer ์‚ฌ์ด์ฆˆ๋ณด๋‹ค ํฐ ๋ฉ”์‹œ์ง€๋ฅผ ๋งŒ๋“ค์–ด ํด๋ผ์ด์–ธํŠธ ์†Œ์ผ“์œผ๋กœ write

4. 3์„ Blocking ๋ชจ๋“œ์™€ NonBlocking๋ชจ๋“œ๋กœ ์ˆ˜ํ–‰

 

[์„œ๋ฒ„ ์ฝ”๋“œ]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/sockios.h>

void errorHandling(char *message);

int main() {
    int serverSocket;
    int clientSocket;

    struct sockaddr_in serverAddr;
    struct sockaddr_in clientAddr;
    socklen_t clientAddrSize;

    printf("server start\n");

    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(serverSocket == -1)
    {
        errorHandling("socket() error");
    }

    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(32452);

    if(bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1)
    {
        errorHandling("bind() error");
    }
    printf("bind ok\n");

    if(listen(serverSocket, 5) == -1)
    {
        errorHandling("listen() error");
    }
    printf("listen ok\n");

    clientAddrSize = sizeof(clientAddr);
    clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrSize);
    if(clientSocket == -1)
    {
        errorHandling("accept() error!");
    }
    printf("accept ok %s \n", inet_ntoa(clientAddr.sin_addr));

    int bufSize = 1024 * 4;
    socklen_t len = sizeof(bufSize);
    setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, &bufSize, sizeof(bufSize));
    getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, &bufSize, &len);
    printf("socket buffer size: %d\n", bufSize);

    // NonBlocking ๋ชจ๋“œ๋กœ ํ…Œ์ŠคํŠธ ํ•  ๊ฒฝ์šฐ ์•„๋ž˜ ์ฃผ์„ ํ•ด์ œ
//    int flag = fcntl(clientSocket, F_GETFL, 0);
//    fcntl(clientSocket, F_SETFL, flag | O_NONBLOCK);

    char message[bufSize * 2];
    for(int i = 0; i < 10; i ++)
    {
        ssize_t nBytes = send(clientSocket, message, sizeof(message), 0);
        if(nBytes == -1)
        {
            errorHandling("write error");
        }
        int remainSize;
        if (ioctl(clientSocket, SIOCOUTQ, &remainSize) == -1)
        {
            errorHandling("ioctl error");
        }
        printf("write message:%zd, remain buf size: %d\n", nBytes, remainSize);
    }

    close(clientSocket);
    close(serverSocket);

    return 0;
}

void errorHandling(char *message)
{
    printf("%s: %s\n", message, strerror(errno));
    exit(1);
}

๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…ํ•˜์ž๋ฉด, Socket Buffer Size๋ฅผ 4,096๋กœ ์ฃผ๊ณ 

ํ•œ ๋ฒˆ์— Socket Buffer Size์˜ 2๋ฐฐ ๋˜๋Š” ํฌ๊ธฐ์˜ ๋ฉ”์‹œ์ง€๋ฅผ 10ํšŒ ๋ณด๋‚ด๋Š” ์ฝ”๋“œ๋‹ค.

 

ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋Š” ํŽธ์˜์ƒ golang์œผ๋กœ ์งฐ๋‹ค... (๊ฐ‘๋ถ„๊ณ )

[ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ]

package main

import (
	"net"
)

func main() {
	println("start")
	addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:32452")
	if err != nil {
		println(err.Error())
		return
	}
	ClientSideCode(addr)
}

func ClientSideCode(addr *net.TCPAddr) {
	conn, err := net.DialTCP("tcp", nil, addr)
	if err != nil {
		println(err.Error())
		return
	}
	println("connect")
	defer conn.Close()
	if err != nil {
		println(err.Error())
	}
	recvBuff := make([]byte, 1024)
	i := 0
	for {
		nBytes, err := conn.Read(recvBuff)
		if err != nil {
			println(err.Error())
			break
		}
		if nBytes == 0 {
			break
		}
		println("nBytes:", nBytes, i)
		i++
	}


	println("Client Exit..")
}

ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋Š” ์„œ๋ฒ„ ์ชฝ์— ์—ฐ๊ฒฐํ•˜๊ณ  Receive๋งŒ ํ•˜๋Š” ์ฝ”๋“œ๋‹ค.

 

์˜ˆ์ƒ๋˜๋Š” ๊ฒฐ๊ณผ๋Š” ๋‹น์—ฐํžˆ Socket Buffer Size๋ณด๋‹ค ํฐ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ƒˆ์œผ๋‹ˆ

Blocking ๋ชจ๋“œ๋ผ๋ฉด ๋ฌดํ•œ Blocking, NonBlocking๋ชจ๋“œ๋ผ๋ฉด ๋ฐ”๋กœ ์—๋Ÿฌ ๋ฆฌํ„ด์ด๋ผ๋Š” ๊ฒฐ๊ณผ๋ฅผ ์˜ˆ์ƒํ–ˆ์œผ๋‚˜

์‹ค์ œ ๊ฒฐ๊ณผ๋Š” ์ข€ ๋‹ฌ๋ž๋‹ค.

 

[Blocking ๋ชจ๋“œ ๊ฒฐ๊ณผ]

server start
bind ok
listen ok
accept ok 10.0.2.2
socket buffer size: 8192
write message:16384, remain buf size: 16384

 

[NonBlocking ๋ชจ๋“œ ๊ฒฐ๊ณผ]

server start
bind ok
listen ok
accept ok 10.0.2.2
socket buffer size: 8192
write message:16384, remain buf size: 16384
write message:15736, remain buf size: 32120
write error: Resource temporarily unavailable

 

Blocking ๋ชจ๋“œ์™€ NonBlocking ๋ชจ๋“œ ๋‘˜ ๋‹ค ์˜ˆ์ƒ๋Œ€๋กœ ๊ฐ๊ฐ ๋ฌดํ•œ Blocking, ์—๋Ÿฌ ๋ฆฌํ„ด์„ ํ•˜์ง€๋งŒ ๋ฒ„ํผ์˜ ์‚ฌ์ด์ฆˆ๊ฐ€ ์ข€ ์ด์ƒํ–ˆ๋‹ค.

๋ถ„๋ช…ํžˆ 8,192(4,096 * 2)๋ผ๋Š” ๋ฒ„ํผ ์‚ฌ์ด์ฆˆ๋ฅผ ์„ค์ • ๋ฐ ํ™•์ธํ–ˆ๋Š”๋ฐ ๊ทธ ์ด์ƒ(16,384)๊นŒ์ง€ ๋ฒ„ํผ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์Œ“์ด๋‹ค๋‹ˆ...

๋ฌด์ˆ˜ํ•œ ์‚ฝ์งˆ ๊ฒฐ๊ณผ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๋ก ์„ ๋‚ด๋ฆฌ๊ธฐ๋กœ ํ–ˆ๋‹ค.

[๊ทธ๋ฆผ 5] ์Šคํƒ ์˜ค๋ฒ„ ํ”Œ๋กœ์šฐ (https://stackoverflow.com/questions/8114280/effect-of-so-sndbuf)

์šฐ๋ฆฌ๊ฐ€ Socket Buffer ์‚ฌ์ด์ฆˆ๋ฅผ ๋ช…์‹œํ•˜์—ฌ ์ง€์ •ํ•˜์˜€๊ณ ,

getsockopt ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ปค๋„๋‹จ์—์„œ Socket Buffer ์‚ฌ์ด์ฆˆ๋ฅผ ์–ด๋–ป๊ฒŒ ์ง€์ •ํ–ˆ๋Š”์ง€ ๋ฐ›์•„์™€๋„ ๊ทธ๊ฒƒ์€ ์ •ํ™•ํ•œ ๊ฐ’์ด ์•„๋‹ˆ๋‹ค.

์‹ค์ œ ์ปค๋„ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” getsockopt๋กœ ๋ฐ˜ํ™˜๋œ ๊ฐ’๋ณด๋‹ค ๋” ๋„‰๋„‰ํ•˜๊ฒŒ ์žก์•„์„œ ๋ฒ„ํผ ์‚ฌ์ด์ฆˆ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

 

์ฐธ๊ณ 


linux man ํŽ˜์ด์ง€
https://linux.die.net/man/2/send
https://linux.die.net/man/7/tcp

TCP/IP ๋„คํŠธ์›Œํฌ ์Šคํƒ ์ดํ•ดํ•˜๊ธฐ - ๊น€ํ˜•์—ฝ ๋‹˜
https://d2.naver.com/helloworld/47667

์Šคํƒ ์˜ค๋ฒ„ ํ”Œ๋กœ์šฐ
https://stackoverflow.com/questions/8114280/effect-of-so-sndbuf
๋ฐ˜์‘ํ˜•

'Language > C++' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[C++] keyword: const  (0) 2020.07.22
[C++11] keyword: final  (0) 2020.07.22
[C++11] keyword: override  (0) 2020.07.22
[C++] keyword: virtual  (0) 2020.07.22
[C++] keyword: public, protected, private  (0) 2020.07.22