[C/C++] Socket Send/Receive Buffer์ ๋ํ ๊ณ ์ฐฐ
๋ชฉ์ฐจ
- Socket Buffer? (Send Socket Buffer / Receive Socket Buffer)
- Socket Buffer ์ฌ์ด์ฆ ๋ณ๊ฒฝ, ์ฌ์ด์ฆ ํ์ธ, ๋ฒํผ ๋ฐ์ดํฐ ํ์ธ
- Socket Buffer ๋์ ํ ์คํธ
Socket Buffer? (Send Socket Buffer / Receive Socket Buffer)
์์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด TCP ํต์ ์์ Application์ด ๋ฉ์์ง๋ฅผ write๋ฅผ ํ๋ค๊ณ ๋ฐ๋ก ๋ฉ์ธ์ง๊ฐ ์ ์ก๋๋ ๊ฒ์ด ์๋๋ค.
์์ผ ๋ฒํผ(Send socket buffer)๋ผ๋ ๋ฒํผ์ ์์ธ ํ ์ ์ ํ ์๊ธฐ์ ์๋๋ฐฉ์๊ฒ ๋ฉ์์ง๊ฐ ์ ์ก๋๊ณ ๋ฒํผ๊ฐ ์ง์์ง๋ค.
๋ฐ๋ ์ชฝ์์๋ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฉ์์ง๊ฐ ์ค๋ฉด ์ผ๋จ, ์์ผ ๋ฒํผ(Receive socket buffer)์ ์ ์ฅ ๋ ํ Application์์ readํจ์ ํธ์ถ์ ํตํด ์์ผ ๋ฒํผ์ ์์ธ ๋ฉ์์ง๋ฅผ ์ฝ์ด ๋ค์ธ๋ค.
๊ทธ๋ ๋ค๋ฉด ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ๋ Send Socket Buffer๊ฐ ๊ฝ ์ฐฌ ์ํ๋ผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
๋ฆฌ๋ ์ค ๊ธฐ์ค์ผ๋ก, ์์ผ์ด 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๋ผ๋ ๊ฐ์ด ๋์๋ค.
๊ทธ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ๋ค.
ํด์ํ์๋ฉด, ์ฐ๋ฆฌ๊ฐ ์ฌ์ด์ฆ๋ฅผ ๋ช ์ํด์ค ๋๋ก ๊ทธ๋๋ก ์ค์ ๋๋ ๊ฒ ์๋๋ค.
์ปค๋ ๋ด๋ถ์์ ๊ฐ์ 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)๊น์ง ๋ฒํผ์ ๋ฐ์ดํฐ๊ฐ ์์ด๋ค๋...
๋ฌด์ํ ์ฝ์ง ๊ฒฐ๊ณผ ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๋ก ์ ๋ด๋ฆฌ๊ธฐ๋ก ํ๋ค.
์ฐ๋ฆฌ๊ฐ 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 |
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
[C++11] keyword: final
[C++11] keyword: final
2020.07.22 -
[C++11] keyword: override
[C++11] keyword: override
2020.07.22 -
[C++] keyword: virtual
[C++] keyword: virtual
2020.07.22 -
[C++] keyword: public, protected, private
[C++] keyword: public, protected, private
2020.07.22