ioLibrary 100% 활용하기 (3)
앞서 살펴 본 ioLibrary의 가장 큰 특징은 다음과 같다.
- 모든 함수의 Success & Fail 처리 : SOCKET ERROR 시 상황 코드
- Blocked & Non-Blocked I/O function
- Datagram Data의 Flexible 처리
각 특징들이 어떻게 활용되는지 하나씩 알아보자
Blocked vs Non-Blocked I/O function
Blocked I/O function 이란, 함수를 호출 할 경우 해당 함수 수행이 완료되기 전까지 return하지 않는 함수이다.
예로, connect(sn, ip, port) 함수를 호출 하였다고 가정할 경우 ip와 port 정보를 갖는 상대방과 접속을 성공하거나 실패할 때 까지 connect() 계속 기다린다. 즉 리턴하지 않고 block 되어진다.
반면, Non-Blocked I/O function는 해당 함수의 수행이 완료되거나, 수행 결과를 기다리지 않고 호출과 동시에 미리 정의된 결과값을 리턴하게 된다. 따라서, 사용자는 함수수행의 결과에 대한 확인를 계속 확인하여야 한다.
Blocked IO Mode
User Application 이 순차적으로 수행될 필요가 있으며, 다른 작업 시간에 영향에 주지 않을 경우 적용될 수 있다.
Blocked IO Mode는 Program이 직관적이여서 Debugging이 용이하나, 함수를 수행하는 동안 Resources를 독점하므로 다른 작업을 수행할 수 없다.
ioLibrary에서 Blocked IO Function은 socket command를 수행하고 그 결과를 확인할 때까지 호출함수가 리턴하지 않음을 의미한다.
아래 코드는 Blocked IO mode로 socket api를 사용하여 Loopback Server 와 Client을 구현한 예이다.
- Client
uint8_t sn = 0; int32_t ret = 0; uint8_t ip[4] = {192,168,0,100}; uint8_t buf[2048] = {0,}; while(1) { ret = socket(sn, Sn_MR_TCP, 3000, 0x00); if(ret < 0) { printf("ERROR : SOCKET open , ErrCode=%d \r\n", ret); close(sn); break; } ret = connect(sn,ip,5000); if(ret < 0) { printf("ERROR : SOCKET Connect , ErrCode=%d \r\n", ret); close(sn); break; } while(1) { ret = recv(sn, buf, sizeof(buf)); if(ret < 0) { printf("ERROR : SOCKET recv , ErrCode=%d \r\n", ret); disconnect(sn); close(sn); break; } ret = send(sn, buf, ret); if(ret < 0) { printf("ERROR : SOCKET send , ErrCode=%d \r\n", ret); disconnect(sn); close(sn); break; } } }
recv()에서 Data를 수신하거나 실패할 경우에만, 다음 함수 Send()를 수행하게 된다. 각 단계 함수 호출이 실패하였을 경우 소켓을 해제하고 while(1)에 의해 소켓 생성, 연결, 전송, 수신을 계속 반복한다.
- Server
uint8_t sn = 0; int32_t ret = 0; uint8_t buf[20] = "Hello, ioLibrary!!!\0"; while(1) { ret = socket(sn, Sn_MR_TCP, 5000, 0x00); if(ret < 0) { printf("ERROR : SOCKET open , ErrCode=%d \r\n", ret); close(sn); break; } ret = listen(sn); if(ret < 0) { printf("ERROR : SOCKET Listen , ErrCode=%d \r\n", ret); close(sn); break; } while(getSn_SR(sn) != SOCK_ESTABLISHED); // Wait until a peer connect to server if(ret < 0) { printf("ERROR : SOCKET Connect , ErrCode=%d \r\n", ret); close(sn); break; } while(1) { ret = send(sn, buf, strlen(buf)); if(ret < 0) { printf("ERROR : SOCKET send , ErrCode=%d \r\n", ret); close(sn); break; } ret = recv(sn, buf, sizeof(buf)); if(ret < 0) { printf("ERROR : SOCKET recv , ErrCode=%d \r\n", ret); close(sn); break; } } }
send()에서 Data를 전송 완료하거나 실패한 후 recv()를 수행한다. 이때 send()가 성공했을 경우만 recv()를 수행해야 정상적인 Loopback이 된다.
각 단계 함수 호출이 실패하였을 경우 소켓을 해제하고 while(1)에 의해 소켓 생성, 연결, 전송, 수신을 계속 반복한다.
Non-Blocked IO mode
User Application 이 순차적으로 수행될 필요가 없거나, 다른 작업을 일정 시간 내에 수행해야 할 경우 사용된다.
Non-Blocked IO Mode는 Program이 작업 간 Schedule을 잘 고려해야 함으로 구현 상의 어려움이 있으며, Debugging이 쉽지 않다.
ioLibrary에서 Non-Blocked IO Function은 socket command만을 수행하고 바로 리턴하거나, 수행 준비가 되어 있지 않을 경우 바로 리턴한다. 이때 Return 값이 SOCK_OK 이라 하더라도 그 결과가 성공했음을 뜻하지는 않는다. 또 SOCK_BUSY인 경우 Command 수행 준비가 아직 되지 않은 상태이므로 반드시 확인하여 해당 command가 수행될 수 있도록 재시도를 하여야 한다.
아래 코드는 Non-Blocked IO mode로 socket api를 사용하여 Blocked IO mode의 Loopback Server 와 Client을 동일하게 순차적으로 수행될 수 있도록 구현한 예이다.
- Client
uint8_t sn = 0; int32_t ret = 0; uint8_t ip[4] = {192,168,0,100}; uint8_t buf[2048] = {0,}; while(1) { if(getSn_SR(sn) == SOCK_CLOSED) { ret = socket(sn, Sn_MR_TCP, 3000, SF_IO_NONBLOCK); // Non-Blocked Mode로 Open if(ret < 0) { printf("ERROR : SOCKET open , ErrCode=%d \r\n", ret); close(sn); break; } while(getSn_SR(sn) != SOCK_INIT); //SOCKET이 생성될 때까지 기다린다. ret = connect(sn,ip,5000); if(ret < 0) { printf("ERROR : SOCKET Connect , ErrCode=%d \r\n", ret); close(sn); break; } } else if(getSn_SR(sn) == SOCK_ESTABLISHED) // SOCKET 이 접속에 성공했다면, { ret = recv(sn, buf, sizeof(buf)); // SOCK_BUSY인 경우 반복 호출한다. if(ret < 0) { printf("ERROR : SOCKET recv , ErrCode=%d \r\n", ret); disconnect(sn); close(sn); break; } else if(ret > 0) // 수신 DATA가 있다면 Loopback 한다. { while(1) // SOCK_BUSY 인 경우 재시도를 위해 while() loop 사용 { ret = send(sn, buf, ret); if(ret < 0) { printf("ERROR : SOCKET send , ErrCode=%d \r\n", ret); disconnect(sn); close(sn); break; } } } } }