[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.221. ์ค๋ช final ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋์ค๋ ๋ฉค๋ฒ ํจ์์ ์์์ ๋ง์ ์ ์๋ค. class Parent final // ํด๋์ค์ final ํค์๋๋ฅผ ์ฌ์ฉ ํ ๊ฒฝ์ฐ 2. ์์ 2.1) final๋ก ์ ์ธ ๋ ํด๋์ค๋ฅผ ์์ํ์ ์ #include using namespace std; class Parent final { public: Parent() { cout -
[C++11] keyword: override
[C++11] keyword: override
2020.07.221. ์ค๋ช ์ค์๋ก ๊ฐ๋ฐ์๊ฐ ์ค๋ฒ๋ผ์ด๋ฉ(overriding)ํด์ผ ํ๋ ํจ์์๋ ๋ถ๊ตฌํ๊ณ ์ค๋ฒ๋ผ์ด๋ฉ์ ํ์ง ์์์ ๊ฒฝ์ฐ ์ปดํ์ผ ํ์์ ์๋ฌ๋ฅผ ๋ฐ์์์ผ ๋ฏธ์ฐ์ ์ค์๋ฅผ ๋ฐฉ์งํ ์ ์๋ค. void override_func() override { cout -
[C++] keyword: virtual
[C++] keyword: virtual
2020.07.221. ์ค๋ช ์์ ํด๋์ค๊ฐ ๋ถ๋ชจ ํด๋์ค๋ฅผ ์์ํ๊ณ , ๋ถ๋ชจ ํด๋์ค์ ํจ์๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉ ํ๋ค๊ณ ๊ฐ์ , ๋คํ์ฑ์ ์ด์ฉํด ๋ถ๋ชจ ํด๋์ค์ ํฌ์ธํฐ๋ก ์์ ์ธ์คํด์ค ์ฃผ์ ๊ฐ์ ์ง์ ํ๊ณ ์ค๋ฒ๋ผ์ด๋ฉ ํ ํจ์๋ฅผ ํธ์ถํ์ ๋ virtual ํค์๋์ ์ ๋ฌด์ ๋ฐ๋ผ ์คํ๋๋ ํจ์๊ฐ ๋ฌ๋ผ์ง๋ค. virtual ํค์๋๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๊ฐ์ ํจ์ ํ ์ด๋ธ์ ๋ง๋ค๊ธฐ ๋๋ฌธ์ ์ฝ๊ฐ์ ์ค๋ฒํค๋๊ฐ ์กด์ฌํ๋ค. ๋ฐ๋ผ์ virtual ํค์๋๋ C++์์ default๊ฐ ์๋๊ณ ๊ฐ๋ฐ์๊ฐ ์ง์ ์ง์ ํด์ค์ผํ๋ค. virtual void speak() = 0; ์์ ๊ฐ์ด virtual ํค์๋ ๋งจ ์ฐ์ธก์ = 0; ์ ์ง์ ํด์ฃผ๋ฉด ํด๋น ํจ์๋ ์์ ๊ฐ์ ํจ์(pure virtual function)๊ฐ ๋๋ค. ์์ ๊ฐ์ ํจ์๋ ์ง์ ํธ์ถ์ด ๋ถ๊ฐ๋ฅํ๋ฉฐ ๋ฐ๋์ ์ค๋ฒ๋ผ์ด๋ฉ(ovโฆ -
[C++] keyword: public, protected, private
[C++] keyword: public, protected, private
2020.07.221. ์ค๋ช public: ์ด๋๊ณณ์์๋ ์ ๊ทผ ๊ฐ๋ฅ protected: ์์๋ฐ๋ ํด๋์ค์ ํํด์๋ง ์ ๊ทผ ๊ฐ๋ฅ private: ์๊ธฐ ์์ ๋ง ์ ๊ทผ ๊ฐ๋ฅ ๋ฉค๋ฒ ๋ณ์๋ ๋ฉค๋ฒ ํจ์ ๊ฐ์ ๊ฒฝ์ฐ ์ ๊ทผ ์ ์ด์๋ ์์ ๊ฐ์ ๊ท์น์ ๋ฐ๋ฅธ๋ค. ํด๋์ค์ธ ๊ฒฝ์ฐ default๋ก private, ๊ตฌ์กฐ์ฒด์ธ ๊ฒฝ์ฐ default๋ก public์ด๋ค. class Parent : (์ ๊ทผ์ ์ด์) Child ์์ ๊ฐ์ด ์์์ ์ ๊ทผ ์ ์ด์๊ฐ ์ฌ์ฉ๋ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ ๊ท์น์ด ์ ์ฉ๋๋ค. public: ๊ธฐ๋ฐ ํด๋์ค์ ์ ๊ทผ ์ ์ด์์ ์ํฅ ์์ด ๊ทธ๋๋ก ์๋ํ๋ค. ์ฆ public์ ๊ทธ๋๋ก public, protected๋ ๊ทธ๋๋ก protected, private๋ ๊ทธ๋๋ก private protected: ํ์ ํด๋์ค ์ ์ฅ์์ public์ protected๋ก โฆ
๋๊ธ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.