일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 자바스크립트
- Node.js
- 쉬운 문제
- 알고리즘
- ip
- 문자열
- Crawling
- 소켓
- TCP
- type challenge
- 그래프
- dfs
- 가천대
- 타입 챌린지
- BFS
- 프로그래머스
- 크롤링
- typescript
- HTTP
- socket
- 수학
- 레벨 1
- 프로그래머스 레벨 2
- Nestjs
- javascript
- 타입스크립트
- HTTP 완벽 가이드
- Algorithm
- 백준
- dp
- Today
- Total
kakasoo
[TCP/IP] 멀티 플렉싱 기반의 서버 전체 코드 및 주석 본문
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#define BUF_SIZE 1024
void ErrorHandling(char* message) {
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
int main(int argc, char* argv[]) {
WSADATA wsaData;
SOCKET hServSock, hClntSock; // 서버 소켓과 데이터 송수신 소켓 생성
SOCKADDR_IN servAdr, clntAdr; // 서버 소켓과 데이터 송수신 소켓의 주소를 의미하는 변수 생성
TIMEVAL timeout; // timeout 값을 저장할 변수 생성
fd_set reads, cpyReads;
int adrSz; // 서버 주소의 크기
int strLen, fdNum;
char buf[BUF_SIZE];
if (argc != 2) { // port 값을 입력받지 않았을 경우, 즉 main 함수의 data가 1인 경우
printf("Usage : %s <port> \n", argv[0]);
exit(1);
}
/* 1. SOCKET 관련 함수 호출, WSAStartup() */
{
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) // 실패 시 에러 메세지 출력
ErrorHandling("WSAStartup() error!");
}
/* 2. server socket 생성 후, server socket 주소 정보 입력 */
{
hServSock = socket(PF_INET, SOCK_STREAM, 0);
memset(&servAdr, 0, sizeof(servAdr));
servAdr.sin_family = AF_INET; // 주소 체계 정보 저장
servAdr.sin_addr.s_addr = htonl(INADDR_ANY); // 접근 가능한 주소 저장, ANY
servAdr.sin_port = htons(atoi(argv[1])); // 접근 가능한 port 저장
}
/* 3. server socket과 주소 정보 간의 결합 */
{
if (bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
ErrorHandling("bind() error!");
}
/* 4. 소켓을 대기 상태로 변경 */
{
if (listen(hServSock, 5) == SOCKET_ERROR)
ErrorHandling("listen() error!");
FD_ZERO(&reads); // fd_set을 모두 0으로 초기화
FD_SET(hServSock, &reads); // hServSock의 관찰 대상을 저장
}
/* 5. 데이터 송수신 */
{
while (1) {
cpyReads = reads; // cpyReads에 reads를 저장, select 이후에 변화가 없는 소켓은 모두 0으로 초기화되니 원본 사용 X
timeout.tv_sec = 5; // timeout을 5 초로 설정
timeout.tv_usec = 5000; // timeout을 5000 마이크로 sec로 설정
if ((fdNum = select(0, &cpyReads, 0, 0, &timeout)) == SOCKET_ERROR)
/*
1번째 매개변수 : 리눅스와의 호환성을 위해 존재하는 의미없는 값.
2번째 매개변수 : 수신된 데이터의 존재 여부를 확인하고자 cpyRead를 넣었다
3번째 매개변수 : 블로킹 없는 데이터 전송 가능 여부를 확인할 의사가 없어 0을 넣었다
4번째 매개변수 : 예외 상황의 발생 여부를 확인할 의사가 없어 0을 넣었다
5번째 매개변수 : timeout을 설정
반환 값은 변화가 발생한 FD의 숫자인데, 오류 발생 시에는 -1이 발생하여 반복문을 빠져나간다.
*/
break;
if (fdNum == 0) // 변화가 없을 경우에는 contiune;
continue;
// 변화가 있을 경우 전체 reads를 순환하며 변화가 발생한 FD를 탐색한다.
for (int i = 0; i < reads.fd_count; i++) {
if (FD_ISSET(reads.fd_array[i], &cpyReads)) // reads.fd_array[i]의 값이 cpyReads에 포함된다면, 표준 입력
{
if (reads.fd_array[i] == hServSock) { // 그 표준 입력이 server socket이라면 연결 요청이 발생한 것
adrSz = sizeof(clntAdr);
hClntSock = accept(hServSock, (SOCKADDR*)&clntAdr, &adrSz); // 연결한다
FD_SET(hClntSock, &reads); // reads에 client socket을 저장한다, 새로 생성한 것
printf("conneced client: %d \n", hClntSock);
}
else { // 서버 소켓이 아닌 경우에 변화 발생 시 read message
strLen = recv(reads.fd_array[i], buf, BUF_SIZE - 1, 0);
if (strLen == 0) { // 읽어들인 것이 0이라면, 연결을 종료한다.
FD_CLR(reads.fd_array[i], &reads);
closesocket(cpyReads.fd_array[i]);
printf("closed client : %d \n", cpyReads.fd_array[i]);
}
else { // 읽어들인 것이 있다면 echo 한다.
send(reads.fd_array[i], buf, strLen, 0);
}
}
}
}
}
}
closesocket(hServSock);
WSACleanup();
return 0;
}
|
cs |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#define BUF_SIZE 1024
void ErrorHandling(char* message) {
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
int main(int argc, char* argv[]) {
WSADATA wsaData;
SOCKET hServSock, hClntSock; // 서버 소켓과 데이터 송수신 소켓 생성
SOCKADDR_IN servAdr, clntAdr; // 서버 소켓과 데이터 송수신 소켓의 주소를 의미하는 변수 생성
TIMEVAL timeout; // timeout 값을 저장할 변수 생성
fd_set reads, cpyReads;
int adrSz; // 서버 주소의 크기
int strLen, fdNum;
char buf[BUF_SIZE];
if (argc != 2) { // port 값을 입력받지 않았을 경우, 즉 main 함수의 data가 1인 경우
printf("Usage : %s <port> \n", argv[0]);
exit(1);
}
/* 1. SOCKET 관련 함수 호출, WSAStartup() */
{
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) // 실패 시 에러 메세지 출력
ErrorHandling("WSAStartup() error!");
}
/* 2. server socket 생성 후, server socket 주소 정보 입력 */
{
hServSock = socket(PF_INET, SOCK_STREAM, 0);
memset(&servAdr, 0, sizeof(servAdr));
servAdr.sin_family = AF_INET; // 주소 체계 정보 저장
servAdr.sin_addr.s_addr = htonl(INADDR_ANY); // 접근 가능한 주소 저장, ANY
servAdr.sin_port = htons(atoi(argv[1])); // 접근 가능한 port 저장
}
/* 3. server socket과 주소 정보 간의 결합 */
{
if (bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
ErrorHandling("bind() error!");
}
/* 4. 소켓을 대기 상태로 변경 */
{
if (listen(hServSock, 5) == SOCKET_ERROR)
ErrorHandling("listen() error!");
FD_ZERO(&reads); // fd_set을 모두 0으로 초기화
FD_SET(hServSock, &reads); // hServSock의 관찰 대상을 저장
}
/* 5. 데이터 송수신 */
{
while (1) {
cpyReads = reads; // cpyReads에 reads를 저장, select 이후에 변화가 없는 소켓은 모두 0으로 초기화되니 원본 사용 X
timeout.tv_sec = 5; // timeout을 5 초로 설정
timeout.tv_usec = 5000; // timeout을 5000 마이크로 sec로 설정
if ((fdNum = select(0, &cpyReads, 0, 0, &timeout)) == SOCKET_ERROR)
/*
1번째 매개변수 : 리눅스와의 호환성을 위해 존재하는 의미없는 값.
2번째 매개변수 : 수신된 데이터의 존재 여부를 확인하고자 cpyRead를 넣었다
3번째 매개변수 : 블로킹 없는 데이터 전송 가능 여부를 확인할 의사가 없어 0을 넣었다
4번째 매개변수 : 예외 상황의 발생 여부를 확인할 의사가 없어 0을 넣었다
5번째 매개변수 : timeout을 설정
반환 값은 변화가 발생한 FD의 숫자인데, 오류 발생 시에는 -1이 발생하여 반복문을 빠져나간다.
*/
break;
if (fdNum == 0) // 변화가 없을 경우에는 contiune;
continue;
// 변화가 있을 경우 전체 reads를 순환하며 변화가 발생한 FD를 탐색한다.
for (int i = 0; i < reads.fd_count; i++) {
if (FD_ISSET(reads.fd_array[i], &cpyReads)) // reads.fd_array[i]의 값이 cpyReads에 포함된다면, 표준 입력
{
if (reads.fd_array[i] == hServSock) { // 그 표준 입력이 server socket이라면 연결 요청이 발생한 것
adrSz = sizeof(clntAdr);
hClntSock = accept(hServSock, (SOCKADDR*)&clntAdr, &adrSz); // 연결한다
FD_SET(hClntSock, &reads); // reads에 client socket을 저장한다, 새로 생성한 것
printf("conneced client: %d \n", hClntSock);
}
else { // 서버 소켓이 아닌 경우에 변화 발생 시 read message
strLen = recv(reads.fd_array[i], buf, BUF_SIZE - 1, 0);
if (strLen == 0) { // 읽어들인 것이 0이라면, 연결을 종료한다.
FD_CLR(reads.fd_array[i], &reads);
closesocket(cpyReads.fd_array[i]);
printf("closed client : %d \n", cpyReads.fd_array[i]);
}
else { // 읽어들인 것이 있다면 echo 한다.
send(reads.fd_array[i], buf, strLen, 0);
}
}
}
}
}
}
closesocket(hServSock);
WSACleanup();
return 0;
}
'프로그래밍 > 네트워크' 카테고리의 다른 글
[TCP/IP] send & recv, MSG_OOB (0) | 2020.07.20 |
---|---|
[TCP/IP] send & recv 입출력 함수 (옵션 정보) (0) | 2020.07.20 |
[TCP/IP] IO 멀티 플렉싱 기반의 서버, 클라이언트 (0) | 2020.07.18 |
[TCP/IP] 다중 접속 서버의 구현 (0) | 2020.07.18 |
[TCP/IP] Domain Name System (0) | 2020.07.18 |