에.... 제목이 너무 장황하네요. 근데, 사실인지라... -_-;

우선, 제 상황은요, 어제까지 시리얼 포트 두개로 파일 전송하는 프로그램 만들려다가...실패하고, 자료를 다시 찾아보는 중입니다.

그래서, 자료를 이해가 안되는 것이 있어서, 고수님들의 명쾌한 해설을.... ^^

아. 그전에 실패했던 원인이, 데이터를 전송했는데 받는 쪽에서 그걸 다 받지 못하는, 즉, 전송이 100만큼되면 80정도만 받는 것이였습니다.

자.... 여기서부터 질문인데요.
1. 우선 , 송신부 데이터보다 수신부 데이터가 작은 점, 또한 송신부에 딜레이(sleep()등) 을 두면 수신율이 올라가는 점(예를들면 80 받던게 85나 90받는다던가...)으로 보아, 이유는 몰라도 송신되는 데이터를 수신부에서 전부 받지 못하는 것이 아닌가 판단했습니다.

그런데... 이게 실제로 가능한가요? 제가 시리얼로 송수신하는 걸 많이 안 해봐서 그런지 몰라도, 꼴랑 2미터짜리 널모뎀 케이블로 PC랑 타겟 보드 연결했는데, 수신부(이게 보드던, 호스트 PC던 증상은 같더군요) 송신하는 걸 다 못 받는다는 게, 상상이 안되더라구요. 실제로 이런 일이 있나요?

2. [비동기 송수신]을 이용하면 된다... 는 해결책이 많이 나와있고, 실제로 많이 이용하시는 듯 한데요. 이해가 안되는 것이,
[serial programming HOW-TO] 에 나와 있는 3가지 방식이면 어느 거라도 되어야 하는 게 정상 아닌가...하는 것이 제 생각이었거든요. 즉, 어떤 모드던 송신측에서는 데이터를 전송할 테고, 수신부에서는 데이터가 버퍼에 들어오면 수신할 테니, 결국 어플리케이션 레벨에서 보면 결국 write 로 보내고 read로 읽어내는 것이 아닌가(물론 , 중간에 0을 보낸다던가 혹은 데이터가 들어오면 signal을 보낸다던가 하는 차이는 있겠지만요) 하는데요. 그런데, 실제로는 다른가요?

3. select()함수를 써서 데이터가 들어올 때 까지 일정 시간 기둘리는 것이 해결책으로 많이 등장하던데요. 이것이 이해가 안 가는 것이,
오히려 시간지연함수(물론 select가 시간지연함수는 아닙니다만)는 송신부에 써야 하는 것 아닌가요? 즉, 송수신 환경에서 수신측이 데이터를 다 못 받고 있으니까, 송신부에서 느리게 송신하고, 수신부에서는 빨리 수신해야 하는데, select()를 쓰면, 물론 시간 안에 데이터가 수신되면 signal을 보내지만, 그래도 그거 처리하는 데도 시간이 걸릴거고, 결정적으로 받는 데이터보다 보내는 데이터가 더 많은 데 왜 수신부에 select()를 쓰는지 이해가 안 가더라구요.

4. 간단한 방법중 하나가 수신부에 버퍼를 늘리는...것을 생각할 수 있다...라는 것이 있던데요.
그런데...그 버퍼라는 것이, rs-232c를 물리적으로 구현하는 칩 안에 있는 버퍼를 이야기하는 것이 아닌가요? 즉, 이미 하드웨어적으로 구현되어 있는 버퍼를 , 어떻게 소프트웨어에서 늘린다는 것인지요? 아니면 이 문장 자체가 다른 의미를 가지고 있나요?

질문이 길어 죄송합니다. 어쩌면 제가 serial 통신의 개념 자체를 잘 못 가지고 있는지도 모르겠습니다만... 고수님들의 조언 부탁드립니다.

그럼. 좋은 하루 되시기 바라며.... 행복하세요. ^^


====================================================================


질문 1) 송신데이터양 <> 수신데이터양답변) 시리얼통신은

질문 1) 송신데이터양 <> 수신데이터양
답변) 시리얼통신은 TCP처럼 데이터 수신후 제대로 수신했는지 확인, 재전송, 에러검출, 흐름제어가 안됩니다.
따라서, 이를(신뢰적인 통신) 응용프로그래머가 구현해야 합니다.
질문 2) 비동기 송수신
답변) 언제 데이터를 보낼지는 알지만, 언제 데이터가 도착할지는 수신 프로그램입장에서 알수 없습니다. 그렇다고 수신하는 측에서 계속 데이터가 오기만 기다릴 수는 없고(다른 작업도 수행해야 하므로), 수신 프로그램이 다른 작업(바이트 수신하는 작업말고)을 수행하는 와중에 도착된 데이터는 일단 특정한 버퍼로 받아놓게 코딩하는 것이 필요합니다. 특정 버퍼의 크기는 클수록 좋겠지요.
*참고: 비동기 송수신이란, 송신측에서 send()할때, 상대가 반드시 recv()를 호출하고 있지 않아도 send()는 동작한다!라는 것입니다. 어떻게? 누가 대신 임시적으로 받아주면 되지요. 누가? 디바이스 드라이버(커널)가. 어디에? 커널 버퍼에. 버퍼크기는? 그때 그때 다른데, 프로그래머가 세팅하기에 달렸지요.
tcp/ip도 비동기 프로토콜임을 참고하시길..
질문 3) select ?
답변) select는 시간지연을 위한 목적이 아니고, 입력(수신데이터가 있나?)을 검사해주는 루틴입니다. 데이터가 수신되면 select에서 탈출하게 되지요. 그러나, 데이터가 만일 하루, 이틀, 10년동안 안오면, 계속 기다릴 수 없겠지요? 따라서, 일정기간동안 입력이 있나를 검사하게 됩니다. 그후 다시 또 시간주고 기다리던가....
또는, 출력을 위해서도 사용되는데, 현재 송신버퍼가 꽉찼는데, 거기다가 데이터를 쓰게 된다면(over run) 문제가 되겠지요? 그래서 송신파일 디스크립터에 select를 걸어 쓸수(보낼수) 있는지를 검사하는 용도로 사용하기도 합니다.
* sleep처럼 대충~ 눈가리고 아웅으로 시간측정해서... 할 수 있으나, 이는 송수신속도(baud rate)나, 시스템사양(예를 들어, 펜티엄3->펜티엄4)이 틀려질 경우, sleep으로 코딩한 부분은 다시 시간측정해서 다시 sleep들어가야 한다는 아픔이 생깁니다.
* 동기화를 위해 sleep을 사용하는 것은 절대 지양해야 합니다.(송수신 속도 바뀔경우 없고, 하드웨어 사양 안바뀐다? 쿵~ ....)
질문 4) 수신버퍼 ?
답변) RS-232C의 수신버퍼 크기는 1바이트 입니다. 하드웨어적으로 말이지요.
디바이스 드라이버에서 데이터가 수신되면 보다 큰 버퍼 영역으로 복사를 해놓을 수 있겠지요? 물론, 버퍼 크기는 1바이트 보다야 크게잡아서리..... 이때, 수신버퍼 영역의 크기가(디바이스 드라이버에서 지정한) 기본크기가 있는데, 경우에 따라, 이 버퍼 크기를 늘려줘야 하는 경우가 있겠지요?
아~ 물론 버퍼 크기야 클수록 좋습니다만........


1. 송신부에서 100을 보냈는데, 수신부에서 80만을 받았다.

1. 송신부에서 100을 보냈는데, 수신부에서 80만을 받았다.
- 정상적으로 짜여진 프로그램이라면 거의 이런 일은 발생하지 않습니다.
- 하드웨어 셋팅을 확인해 보세요 boud, parity...
- 시리얼은 단순한 하드웨어 흐름제어는 가능하지만 TCP와 같은 신뢰성은 매우 떨어집니다. (대신 매우 심플하지만요)
2. 비동기송수신은 받던지 말던지 보낸다로 생각하면 될 것같은데...이것과는 별개 인것 같습니다. 시리얼은 일부러 그러지 않는한 비동기 송수신 입니다.
(TCP의 경우 핸드쉐이킹이 필요합니다만...)
3. select는 머... 여러가지 기능이 있는데 또 위 문제와는 별개입니다. read 함수는 일부러 그러지 않는한 특정 사이즈 만큼 받을 때까지 블락되니깐요.
4. 수신부의 버퍼가 무엇을 말하는 것인지는 모르겠지만, 디바이스 드라이버에서의 수신 버퍼는 우선 생각하지 마시고(아마도 최적화 되어 있지 않을까요?) read 함수의 버퍼만 생각하는게 낫지 않을까요?(시리얼의 수신 버퍼의 문제일리는 없을 것 같아서....)

경험상 통신시 데이터가 적게 수신되는 경우는 생각하시는 것처럼 복잡하지 않습니다. 즉 간단한 실수 였다는 거죠
1. 케이블 문제
2. 시리얼 셋팅 문제
3. 송신측 APP 단의 버퍼 크기 문제
4. 보내려고 하는 size 문제
5. 수신측 APP 단의 버퍼 문제
6. 받으려고 하는 size 문제
7. 매우 드물지만 케이블의 길이 등이 스펙의 권고안보다 긴경우 에러가 생길 수 있지만 100:80의 비율은 아닙니다.


1. 답변송신부에서 100을 보냈는데 수신부에서 80만 받는 경우는

1. 답변
송신부에서 100을 보냈는데 수신부에서 80만 받는 경우는 나올수 있습니다. 물론 지금 말씀하신 데이터 정도는 크게 문제될 것 같지는 않지만 가능성은 있습니다. 아실테지만 시리얼통신은 신뢰성 통신 방식이 아닙니다. 따라서 시리얼 데이터를 받는 부분에서 하드웨어 버퍼 또는 디바이스 드라이버 버퍼의 양이 너무 빨리 들어오는 데이터양에 못견뎌 데이터가 손실될 수 있습니다. 따라서 송신측에서 시간 간격을 두면 데이터가 다 받아지는 것입니다.

2. 답변
동기 방식이냐 비동기 방식이냐는 효율적 측면에서 다릅니다. 우리가 TCP/IP에서 동기/비동기 방식을 구분해서 사용하는 것또 같은 맥락이라고 생각합니다.

3. 답변
이 부분은 말씀하신 분께서 뭔가 착각하고 계신것 같은데요... 송신측에서 시간을 지연시켜 전송하는 것은 통신을 정삭적으로 하기 위한 하나의 트릭일 뿐이지 그런 방식을 언젠가는 큰 재앙을 불러옵니다. 따라서 양측의 APP 프로토콜 설계시 이런 것들을 고려해야합니다. 그 프로토콜을 정의하고 데이터를 안전하게 수신할 수 있도록 해야겠지요... 데이터를 천천히 보냈더니 수신측에서 데이터를 다 받네... 이런 방법은 옳지 않습니다. 시리얼통신 속도를 높이는 것도 한 방법이 될 수 있겠네요... 아니면 하드웨어 또는 소프트웨어 흐름제어를 사용하는 것도 하나의 방법입니다.(성능은 좀 떨어지겠지만...)

4. 답변
버퍼의 크기를 늘리는 것도 한 방법입니다. 하지만 시리얼 통신은 전송속도가 매우 느린 통신 방법중 하나입니다. 9600 baud를 사용할 경우 1초에 보낼수 있는 데이터의 양은 약 900 바이트 정도입니다. 따라서 이런 이론적인 내용을 분석하고 본인의 프로그램에 적용하는 것이 옳다고 생각되네요...

미흡한 답변이지만 도움이 되었으면 합니다.


WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,