지도 교수 : 석승준 교수님


수행 Project :

1. 교량 모니터링 시스템 개발 ( 정적 교량 / 일반 교량)

개발 기간 : 6개월 

내용 : 여러 종류의 센서 네트워크를 사용하여 교량 판의 휘어짐과 교량 지지선의 강도 등을 추적하여 문제 예방 및 발생 추적을 제공하기 위한 모니터링 시스템


2. 교량 모니터링 시스템 개발 ( 동적 교량 / 구름 사다리 등의 중간 지지대가 없는 사람 전용 교량)

개발 기간 : 4개월

내용 : 급격한 날씨 변화 등으로 인한 자연재해로 발생 가능한 문제 발생 예방 및 추적을 제공하기 위한 모니터링 시스템


3. BGP Server 모니터링 시스템

개발 기간 : 8개월

내용 : 백본에 있는 BGP의 정보를 추출하여 해킹 및 특정 데이터의 지속적인 추출 및 추적 시스템 개발


세부 전공 :
(연구경력 및 관심분야)


세부 전공 : 무선통신 (802.11b 대역에서의 TCP/UDP 성질의 특성)

관심 분야 : 

1) 실시간 원격 제어 시스템

- 해외의 원거리를 최저 지연으로 장비를 제어할 수 있는 시스템

2) 시장 분석 시스템 

- 네트워크 패킷들을 무작위로 검출하여 정보를 산출, 이를 토대로 예측되는 시장과 경제의 변화를 추적하는 시스템

3) Wifi 핸드오버 시스템

- 통신 회사의 데이터망으로 실시간 데이터를 사용하다 특정한 장소들에서 자동으로 데이터가 연결되어 이동되는 방법

예 ) 모바일 모니터링 장비로 건물의 이동함에 따라 각각의 최적 AP에서 끊기지 않는 데이터를 전달하는 방법

      - 현재도 구현은 가능하나 많은 부분에 있어서 질적 한계가 있으므로 이를 개선하는 것이 목표

      

입사후 희망 연구분야      

      

1) 유비쿼터스 분야

- OpenFlow 및 유사 게이트웨이 제어/관리 시스템 


2) 스트리밍 솔루션

- RTSP 2.0 및 적극적 리얼타임 스트리밍 프로토콜들과 관련된 연구 및 개발 분야


3) 네트워크 솔루션

- 소프트웨어형 네트워크 라우터(L4), RTN(Real Time Network) 등

      

      

      

      

2012.09.21~진행 중


프로젝트 명 : KT Distribution CDN Server

직책 : 대리

솔루션 : 서버 모듈, 시뮬레이터


- 서버 모듈 : CDN Gateway (Distribution Sheduler/Content management/Recovery[failover])

* Post Protocol 

* Multi-older and Distribution performance support

* DB linkage (statistics support)

* Distribution Recovery


2012.06.11~진행 중


프로젝트 명 : KT Vod & Live Streaming System (RTSP/HTTP)

직책 : 대리

솔루션 : 서버 모듈, Client SDK, 시뮬레이터


- 서버 모듈 : URL Transfer Module(php 기반)

Progressive Download Module (Apache 기반)

- Client SDK : RTSP/HLS SDK

* Recovery 기능 추가 

* RTP, RTCP, RTSP 기능 추가 

* HLS Smooth Zapping 기능 추가

* DB linkage

* Distribution Recovery


2012.11.08~ 진행 중


프로젝트 명 : SK Legacy RTSP STB iSQMS(Smart Quality Management System)


2012.03.26~2012.10.01


프로젝트 명 : SK RTSP NewSTB (가온 전자STB)


2011.11.11~진행 중


프로젝트 명 : LGU+ CCDP(Common content distribution platform)

직책 : 대리

솔루션 : CDS, Client SDK, Indexer, 시뮬레이터


- CDS IEC(IO Event Controller) Module : Process Manager (Event, Schedule, Priority)

- CDS CCP(Core Communication Protocol) Module : Network Manager (UDP/TCP Communication, Parsing, HashTable Transaction)

- CDS TC(Transmission child-processes) Module : Transmission Manager (Traffic, Channel, Rate, Recovery)

- Client SDK : RTSP/HLS/ SDK


2012.02.06~2012.09.09


프로젝트 명 : SK Legacy RTSP STB iSQMS(Smart Quality Management System)


2012.01.27~2012.03.21


프로젝트 명 : SK RTSP Service Improvement 


2011.12.15~2012.02.29 


프로젝트 명 : SK RTSP CUG(Closed User Group) 2.0


2011.05.16~2012.04.27


프로젝트 명 : SK Integration Legacy STB (CUG & VOD / Samsung, Hyunday, Celrun STB)


2011.02.21~2011.04.05


프로젝트 명 : SK Apple TV


2010.11.01~2010.12.20


프로젝트 명 : 동국대 IPTV


2010.06.21~2011.02.21


프로젝트 명 : SK RTSP CUG(Closed User Group) 1.0


2010.06.07~2011.06.22


프로젝트 명 : SK RTSP VOD(Samsung STB)


* 열심히 흘린 땀들은 거짓말을 하지 않는다.

 회사에 입사를 하고 나서 쉴 새 없이 계약들이 체결되었고 지속적으로 프로젝트가 진행되었습니다. 그리고 새로운 프로젝트를 수행할 때마다 새로운 시스템이 추가되어 다양한 기술에 대해 빠른 대처가 요구되었었습니다.

이에 작업의 진행은 먼저 RFC 확인, Open-Source 검색, 있다면 분석 및 모듈화 하여 사용할 수 있는 라이브러리로 최적화하여 시뮬레이션을 해 보거나, 브레인 스토밍을 통해 기능명세서 작성 후 상위 디자인, 하위 디자인, 모듈화 및 통합 개발을 수행하여 일련의 프로세스를 통해 형상관리를 하는 과정을 진행해 왔었습니다.

이러한 새로운 기능과 새로운 시스템의 개발은 실패에 대한 많은 인내와 지속적인 학습과 노력의 필요성을 요구하였습니다.

그리고 짧은 시간과 부족한 인력은 효율적인 성과를 위해 항상 작업을 확인하고 우선순위를 관리, 작업의 문서화를 중요시하여 다음에 즉시 사용할 수 있는 대비를 하게하여 회사의 능률을 높일 수 있도록 만들어야 했습니다. 

간혹 주위 분들께서 너무 힘들지 않냐고 물어보십니다. 하지만 저는 이렇게 생각 합니다. 시간과 노력 없이 얻을 수 있는 것들이 얼마나 되겠느냐고, 덕분에 이만큼 많은 능력들을 얻게 된 것이지 않겠냐고 말입니다.




* 보석은 어두울 때 더 빛난다

 입사를 하고 회사 내 경력자들이 많이 이직을 하는 사태가 벌어지는 과정에서 주역 상품 솔루션이 사실 완성품이라 하기에 많은 문제점을 가지고 있다는 것을 확인할 수 있었습니다. 하지만 이미 대기업과 처음으로 계약을 맺은 상태였기에 시간 내 해당 제품의 성능이 만족하는 수준으로 제공되어야만 했었습니다. 팀원이라고는 인도에서 영입된 개발과장과 본인 두 명이 다였었기에, 시간이 소중하기가 황금 같던 시기였습니다. 1차 BMT가 마무리될 때까지 3주간 회사에서 먹고 자는 생활을 하며 눈을 마주치면 솔루션의 동작과 성능 그리고 시나리오에 대해 모든 방법을 동원해 아이디어를 내고 확인을 하는 과정을 여러 번 거쳤었습니다. 2달이 지나고 최종 BMT까지 많은 시련이 있었지만, 상용화를 시연하고 박수를 받는 과정에서 '회사의 솔루션이 내 손으로 완성되었구나...' 하는 뿌듯함에 며칠을 들뜬 마음으로 설레어 잠을 설쳤던 경험이 있습니다. 요즘도 가끔 이전 생각을 하면서 많이 힘들었지만, 책임감 하나에 열심히 했던 모습을 잃지 않으려 노력하고 있습니다.

 

 

 * 실수는 일상의 단점으로부터 만들어진다.

 회사 내 특정 텔레콤 프로젝트를 전담으로 맡게 됐었습니다. 그러다 보니, 견적서 및 제안서를 작성하는 일도 더러 생기게 되었습니다. 하지만 경험 미숙으로 계속 재요청을 받게 되었으며, 해결을 위한 시간 투자가 점차 늘어나게 되어 타 업무에 문제가 발생하는 상황이 되었었습니다. 

마지막 회의를 하면서 상대 담당자분들이 조언을 해 주시기를, 개발자와 같은 전문지식이 풍부한 사람이 아닌 사람들에게 제안서를 만들어 제공할 때에는 더욱 쉽고 상세하게 고객의 눈높이에 맞춰야 한다는 말씀이였습니다. 그전에는 개발 담당자가 아닌 이상, 말로 구체적인 표현을 하는데 어려움이 많다는 것을 인지하지 못했었습니다. 그저 어설픈 의사 전달을 독단적인 판단으로 구체화 시키고 있었다는 문제를 그때야 알게 되었던 것입니다.

지금은 문제를 고치기 위해 노력을 많이 하고 있습니다.

개발자 간에서도 담당 분야가 틀리면 이러한 문제가 일어날 수 있기 때문에, 여러 표현으로 의사 전달을 하고, 반복적으로 확인하여 같은 문제가 발생하지 않도록 수시로 하는 행동들을 한 번 더 확인하려 노력합니다.



 * 혼자서 할 수 있는 능력, 남들과 같이할 수 있는 능력

 회사에서 맡아 담담했던 부분은 RTSP/RTP/RTCP Client SDK, Indexer, 네트워크 모니터링 시스템, 배포 서버군(CDN), CDN Controller 서버, HLS 모듈, 등이 있으며, 차기 솔루션을 위해 관련 스트리밍 Protocol 및 Cloud와 같은 시스템에 대해 팀 내 Study 및 준비를 하고 있었습니다. 기본적으로 다루는 언어는 C이고, C++는 일반적인 작업을 수행할 수 있습니다. 테스트를 위해 Web 개발도 일반적인 수준의 개발을 수행하였으며, DB 테이블 설계 등의 작업도 지속해서 지원 및 수행해 왔었습니다. 기반 개발 환경이 리눅스였기에 다양한 스크립트와 쉘 툴들을 사용하였으며, 기본적인 네트워크 관련 커널 세팅 환경과 이에 따른 성능 변화에 대해 이해를 하고 있습니다.

 팀장이 외국인이다 보니 외부의 대부분 회의를 제가 담당해야 하는 경우가 태반이었으며, 파견 및 협업 작업 또한 혼자 이동하여 수행하는 경우가 많았습니다. 이에 다양하고 많은 의사결정의 상황이 있었으며 이러한 일들은 업무의 기준이라는 것을 만들어 주었습니다. 개발은 크게 세 가지 작업들로 나누어 진다 생각합니다. 순수 기능 개발, 정책 결정, 앞선 두 사항을 지탱해주는 시나리오입니다. 이 기준에 맞추어 저 자신을 평가하자면 모든 부분에서 중간 이상의 능력치를 가지고 있다고 확실히 말할 수 있을 것 같습니다.





 * 장점

 책임감이 매우 강하며 팀원의 분위기 매이커이자 문제 해결을 위한 리더로 역할을 잘 수행합니다. 모르는 사람들과도 금세 친하게 되는 사교성과 누구라도 한번 알고 나면 처음 보는 성향이라 독특하지만 정말 마음에 든다고 듣는 호감형 인간입니다.


 * 단점

 한 가지에 집중하다 보면 쉬는 시간을 본인에게 잘 할애하지 못하여 문제 해결을 위해 장기적인 시간이 필요한 경우에 몸이 많이 고생하는 편입니다. 주변에 있는 사람들을 챙기고 도우려는 심리가 항상 존재하기에 이를 이용하고 다가서는 사람이라는 것을 알면서도 선뜻 시간을 할애하는 경우가 더러 있어 이 또한 몸이 많이 고생하는 경우가 됩니다. 외향적인 성향으로 보이나 속으로는 생각이 많고 감수성이 깊은 편이라 사람이나 상황에 대해 더 많은 고민으로 마음이 고생을 자주 하는 편입니다.


 

 

  * 내일보다 더 앞선 미래를 위해

 사람이 병이 심각해 치료를 받을 때, 의사는 몸의 여러 이상한 부위 중 제일 위험한 곳이 어딘지를 먼저 확인하고 이를 먼저 치료합니다. 인도와 미국에서 짧게나마 IT의 현실을 보고 온 사람으로 대한민국의 후배들에게 알려줘야겠다고 마음먹은 것이 있다면, 일단 동작하게 하는 것도 중요하지만 '어떻게 만들고 어떻게 관리할 것인가?'라는 질문이 사실 더 중요하다는 것입니다. 한국인들과 같이 협업했던 다양한 외국인들이 평가하는 대한민국은 너무 조급한 나머지 이러한 부분에 치명적인 약점을 가지고 있다고 했던 기억이 있습니다. 이에 지금 이 질문에 대해 걱정을 하고 저 자신을 생각한다면, 아마도 10년의 세월이 지나 더 많은 지식의 질이 더해져 있을 때 이를 바탕으로 책을 내고, 웹 커뮤니티를 형성하여 영상과 자료로 많은 사람에게 제 지식을, 혹은 자신들의 지식을 좀 더 체계적으로 공유할 수 있는 것과 장소를 만들고 제공하는 서포터가 되고 싶다는 생각이 있습니다.

 

이 에러때문에 중요한 컴퓨터를 재설치 하는 문제가 있었다.

다른 컴퓨터에도 또 또 또!!!! 나타나서

이번엔 시간을 많이 들여 검색과 시도를 했다

 

결론은 다음과 같다.

 

sudo apt-get --purge --reinstall install gdm

chmod -R 760 /home/levan/

두개를 하면 된다.

'Linux > kernel' 카테고리의 다른 글

ubuntu 64bit 환경에서 32bit 크로스컴파일러 사용하기  (0) 2012.10.24
ubuntu 계정 추가  (0) 2012.09.18
Network 설정  (0) 2012.05.31
STB에서 top이 안먹힐때  (0) 2011.06.08
mysql 프로시저 Linux/C/C++ 2012. 11. 7. 20:38

http://blog.naver.com/PostView.nhn?blogId=cache798&logNo=130080151940&categoryNo=68&viewDate=&currentPage=1&listtype=0

ubuntu 11.4를 설치하고 Arm 컴파일러를 http://www.codesourcery.com/sgpp/lite/arm에서 다운받았다.

Makefile에서 컴파일러 PATH를 설정하고 u-boot 를 빌드하려고 했더니 그런 파일이 없다고 에러가 나왔다.

설치된 폴더에서 파일이 있는 폴더로 가서 컴파일러 테스트를 해보아도 

"-bash: ./arm-none-linux-gnueabi-gcc : 그런 파일이나 디렉터리가 없습니다"

라는 메세지만 나오네 ㅠㅠ; 

그렇다면 PATH설정이 잘못된건 아니고....

원인은 64bit 환경에서 32bit용 컴파일러를 실행시키려 했기 때문이었다.

해결방법은 ia32-libs 패키지를 설치해주면 된다.


sudo apt-get install ia32-libs


설치하면 결과는 잘된다. 

이 간단한걸 몰라서 3시간 동안 삽질했다. ㅠㅠ;

'Linux > kernel' 카테고리의 다른 글

could not update iceauthority file /home/user/.iceauthority  (0) 2012.11.11
ubuntu 계정 추가  (0) 2012.09.18
Network 설정  (0) 2012.05.31
STB에서 top이 안먹힐때  (0) 2011.06.08

P 소켓 프로그램을 작성해 보겠습니다. 본 포스트는 동영상을 먼저 보신 후, 본문 내용을 보시면 이해하시기 편합니다.

TCP/IP 통신 함수 사용 순서

TCP/IP 예제 소개

TCP/IP 예제를 서버와 클라이언트로 나누어서 설명을 드리도록 하겠습니다.

  1. 서버와 클라이언트는 port 4000번을 사용
  2. 클라이언트프로그램에서 서버에 접속하면 실행할 때 입력받은 문자열을 전송
  3. 서버는 클라이언트로부터 자료를 수신하면 문자열 길이와 함께 수신한 문자열을 클라이언트로 전송

서버 프로그램

서버 프로그램에서 사용해야할 함수와 순서는 아래와 같습니다.

우선 socket 부터 만들어야 합니다. TCP/IP에서는 SOCK_STREAM을 UDP/IP에서는 SOCK_DGRAM을 사용하는 것을 참고하여 주십시오. socket()에 대한 더 자세한 말씀은 "Unix C Reference의 11장 7절 소켓 열고 닫기"를 참고하십시오.

int server_socket;

server_socket = socket( PF_INET, SOCK_STREAM, 0);
if (-1 == server_socket)
{
printf( "server socket 생성 실패");
exit( 1) ;
}

bind() 함수를 이용하여 socket에 server socket 에 필요한 정보를 할당하고 커널에 등록

  1. 만들어진 server_socket 은 단지 socket 디스크립터일 뿐입니다.
  2. 이 socket에 주소를 할당하고 port 번호를 할당해서 커널에 등록해야 합니다.
  3. 커널에 등록해야 다른 시스템과 통신할 수 있는 상태가 됩니다.
  4. 더 정확히 말씀드린다면 커널이 socket 을 이용하여 외부로부터의 자료를 수신할 수 있게 됩니다.
  5. socket에 주소와 port 를 할당하기 위해 sockaddr_in 구조체를 이용합니다.

    struct sockaddr_in server_addr;

    memset( &server_addr, 0, sizeof( server_addr);
    server_addr.sin_family = PF_INET; // IPv4 인터넷 프로토롤
    server_addr.sin_port = htons( 4000); // 사용할 port 번호는 4000
    server_addr.sin_addr.s_addr = htonl( INADDR_ANY); // 32bit IPV4 주소

    if( -1 == bind( server_socket, (struct sockaddr*)&server_addr, sizeof( server_addr) ) )
    {
    printf( "bind() 실행 에러n");
    exit( 1);
    }

  6. htonl( INADDR_ANY) 는 주소를 지정해 주는 것으로 inet_addr( "내 시스템의 IP ")로도 지정할 수 있습니다. 그러나 프로그램이 실행되는 시스템 마다 IP 가 다를 것이므로 주소 지정을 고정 IP로 하지 않고 htonl( INADDR_ANY) 를 사용하는 것이 편리합니다.

이제 listen() 함수로 클라이언트 접속 요청을 확인합니다.

if( -1 == listen( server_socket, 5))
{
printf( "대기상태 모드 설정 실패n");
exit( 1);
}

  1. listen() 함수를 호출하면 클라이언트의 접속 요청이 올 때 까지 대기 상태가 됩니다. 즉, 블록된 모습이 되죠.
  2. 함수가 리턴이 되었을 때에는 클라이언트의 접속이 요청 되었다든지, 아니면 에러가 발생했을 경우입니다.
  3. 에러 없이 함수가 복귀했다면 클라이언트의 접속 요청입니다.
  4. 접속 요청을 허락합니다.

클라이언트 접속 요청에 따라 accept()로 접속을 허락합니다.

  1. accept()로 접속 요청을 허락하게 되면 클라이언트와 통신을 하기 위해서 커널이 자동으로 소켓을 생성합니다.
  2. 이 소켓을 client socket이라고 하겠습니다.
  3. client socket 정보를 구하기 위해 변수를 선언합니다. 그리고 client 주소 크기를 대입합니다.

    int client_addr_size;

    client_addr_size = sizeof( client_addr);

  4. accept()를 호출 후에 에러가 없으면 커널이 생성한 client socket 을 반환해 줍니다.

    client_socket = accept( server_socket, (struct sockaddr*)&client_addr,
    &client_addr_size);

    if ( -1 == client_socket)
    {
    printf( "클라이언트 연결 수락 실패n");
    exit( 1);
    }

이제 client socket까지 만들어 졌으므로 read(), write() 함수를 이용하여 자료를 송수신 할 수 있습니다. read() 함수를 이용하여 클라이언트로부터 전송되어 오는 자료를 읽어 들입니다.

read ( client_socket, buff_rcv, BUFF_SIZE);

  1. read() 를 이용하여 클라이언트로부터 전송된 자료를 읽어 들입니다.
  2. 만일 클라이언트로부터 전송된 자료가 없다면 송신할 때 까지 대기하게 됩니다. 즉, 블록된 모습이 됩니다.

이번에는 wirte() 함수를 이용하여 클라이언트도 데이터를 전송합니다.

  1. 수신된 데이터의 길이를 구하여 전송 데이터를 준비합니다.

    sprintf( buff_snd, "%d : %s", strlen( buff_rcv), buff_rcv);

  2. write() 를 이용하여 클라이언트로 자료를 송신합니다.

    write( client_socket, buff_snd, strlen( buff_snd)+1); // +1: NULL까지 포함해서 전송

작업이 완료되면 close() 를 이용하여 client socket 을 소멸 시켜 데이터 통신을 종료합니다.

close( client_socket);

클라이언트 프로그램

클라이언트 프로그램은 서버에 비해 간단합니다. 바로 설명 들어갑니다.

socket() 을 이용하여 소켓을 먼저 생성합니다.

int client_socket;

client_socket = socket( PF_INET, SOCK_STREAM, 0);
if( -1 == client_socket)
{
printf( "socket 생성 실패n");
exit( 1);
}

connect()를 이용하여 서버로 접속을 시도합니다.

  1. 주소 정보에 서버의 주소와 포트번호를 지정하고
  2. 서버와의 연결을 시도합니다.
  3. 예제에서는 시스템 자기를 가르키는 IP, 127.0.0.1 을 사용했습니다.

    struct sockaddr_in server_addr;

    memset( &server_addr, 0, sizeof( server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons( 4000);
    server_addr.sin_addr.s_addr= inet_addr( "127.0.0.1"); // 서버의 주소

    if( -1 == connect( client_socket, (struct sockaddr*)&server_addr, sizeof( server_addr) ) )
    {
    printf( "접속 실패n");
    exit( 1);
    }

  1. 접속에 성공하면 데이터를 전송합니다.

    write( client_socket, argv[1], strlen( argv[1])+1); // +1: NULL까지 포함해서 전송

  2. 자료를 수신하고 화면에 출력합니다.

    read ( client_socket, buff, BUFF_SIZE);
    printf( "%sn", buff);

  3. socket 을 소멸하여 통신 작업을 완료합니다.

    close( client_socket);

서버 프로그램 소스

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#define  BUFF_SIZE   1024

int   main( void)
{
   int   server_socket;
   int   client_socket;
   int   client_addr_size;

   struct sockaddr_in   server_addr;
   struct sockaddr_in   client_addr;

   char   buff_rcv[BUFF_SIZE+5];
   char   buff_snd[BUFF_SIZE+5];



   server_socket  = socket( PF_INET, SOCK_STREAM, 0);
   if( -1 == server_socket)
   {
      printf( "server socket 생성 실패n");
      exit( 1);
   }

   memset( &server_addr, 0, sizeof( server_addr));
   server_addr.sin_family     = AF_INET;
   server_addr.sin_port       = htons( 4000);
   server_addr.sin_addr.s_addr= htonl( INADDR_ANY);

   if( -1 == bind( server_socket, (struct sockaddr*)&server_addr, sizeof( server_addr) ) )
   {
      printf( "bind() 실행 에러n");
      exit( 1);
   }

   while( 1)
   {
      if( -1 == listen(server_socket, 5))
      {
         printf( "대기상태 모드 설정 실패n");
         exit( 1);
      }

      client_addr_size  = sizeof( client_addr);
      client_socket     = accept( server_socket, (struct sockaddr*)&client_addr, &client_addr_size);

      if ( -1 == client_socket)
      {
         printf( "클라이언트 연결 수락 실패n");
         exit( 1);
      }

      read ( client_socket, buff_rcv, BUFF_SIZE);
      printf( "receive: %sn", buff_rcv);
      
      sprintf( buff_snd, "%d : %s", strlen( buff_rcv), buff_rcv);
      write( client_socket, buff_snd, strlen( buff_snd)+1);          // +1: NULL까지 포함해서 전송
      close( client_socket);
   }
}

클라이언트 프로그램 소스

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#include "sample.h"

#define  BUFF_SIZE   1024

int   main( int argc, char **argv)
{
   int   client_socket;

   struct sockaddr_in   server_addr;

   char   buff[BUFF_SIZE+5];

   client_socket  = socket( PF_INET, SOCK_STREAM, 0);
   if( -1 == client_socket)
   {
      printf( "socket 생성 실패n");
      exit( 1);
   }

   memset( &server_addr, 0, sizeof( server_addr));
   server_addr.sin_family     = AF_INET;
   server_addr.sin_port       = htons( 4000);
   server_addr.sin_addr.s_addr= inet_addr( "127.0.0.1");

   if( -1 == connect( client_socket, (struct sockaddr*)&server_addr, sizeof( server_addr) ) )
   {
      printf( "접속 실패n");
      exit( 1);
   }
   write( client_socket, argv[1], strlen( argv[1])+1);      // +1: NULL까지 포함해서 전송
   read ( client_socket, buff, BUFF_SIZE);
   printf( "%sn", buff);
   close( client_socket);
   
   return 0;
}

참조 : http://smeffect.tistory.com/entry/01-네트워크-프로그래밍-TCPIP-소켓-프로그래밍

참조 : http://nenunena.tistory.com/60

1 alarm(TIMEOUT);
2 pause();
3 alarm(0);
..

위와 같이 alarm()을 사용해서 TIMEOUT을 구현하는 경우 race condition 문제가 발생할 가능성이 있다. 1번에서 알람이 설정되고 2번이 실행되기 전에 프로세스 스케줄링이 변경되서 다른 프로세스가 실행되는 경우(서버가 과부하인 상태이고 TIMEOUT이 짧을때), 2번이 실행되기 전에 alarm이 만료되어서 signal을 받을수 있다. 그렇게되면 pause()는 무한정 블럭되어버린다.

이 문제를 해결하는 방법은 몇가지가 있는데 내가 자주 사용하는 방법은 sigsetjmp/siglongjmp를 사용하는 방법이다.

/* SIGALARM handler */
void
sigalrm_handler(int signo)
{
     siglongjmp(jmpbuf, 1);
}

int
main(void)
{
...

       /* SIGALRM에서 사용할 시그널 점프 등록 */
       if(sigsetjmp(jmpbuf, 1) != 0) {
           goto timeout;
       }

       /* 알람 설정 후 신호대기 */
       alarm(TIMEOUT);
       pause();

timeout:
       alarm(0);

...
}

위 코드에서는 SIGALRM이 발생하면 시그널 핸들러를 실행하고 sigsetjmp 위치로 점프한다. 그리고 다시 timeout으로 goto하기 때문에 race condition 상황이 발생해도 pause()는 실행되지 않는다.

'Linux > C/C++' 카테고리의 다른 글

mysql 프로시저  (0) 2012.11.07
Thread와 Signal  (0) 2012.10.19
log file format 조건  (0) 2012.10.19
전처리기 #define do{ 문장1; 문장2; 문장3 }while(0) 사용...  (0) 2012.09.24
UCDParser result to analysis a indexing content  (0) 2012.08.29
Thread와 Signal Linux/C/C++ 2012. 10. 19. 17:59


특정 thread에만 alarm을 사용하고 싶습니다.  signal / 네트워크프로그래밍

2012/05/03 15:27

복사http://blog.naver.com/nds239/10137957769

전용뷰어

출처 : http://rootfriend.tistory.com/161


환경은 1 process, multi-thread라 가정합니다.

그리고 각각의 sub-thread들은 recv 대기중에 있으며 저는 원하는 시간에 이들을 깨우기 위해 alarm()시스템 콜을 사용하려고 합니다.
(time out에서 일반적으로 쓰는 방법, 즉 select 대기나 SO_RCVTIMEO등은 사용할 수 없다고 가정합니다.)

그러나 문제는 alarm이라는 system call이 per-thread가 아닌 per-process라는데 문제가 있습니다.

가령, multi-thread환경에서

alarm(5);
recv(...);
alarm(0);

과 같은 코드를 작성하면 불행하게도 recv에서 대기하고 있던 여러개의 thread가 동시에 wake-up하기 때문에 원하는 바대로 동작할 수 없습니다.

alarm이 아닌 pthread_kill을 사용하는 경우에

pthread_kill(pthread_self(), SIGALRM);
recv(...);

와 같은 Code에서 보듯이 recv에서 대기하는 것이 불가능하게 됩니다.

그래서 결국은 alarm()을 이용하여 SIGALRM을 발생시키면서도 모든 thread가 아닌 특정 thread에서만 SIGALRM을 받을 수 있는 제 3의 방법이 있어야 합니다.

이런 경우를 직접 Coding해 보신 분이 계신지 궁금합니다.

고수의 친절한 가르침을 기대합니다.

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

일단 multi-thread에서 가장 다루기 힘든 부분 중 하나가 signal 처리입니다. 힘든 건 둘째치고, platform에 따라서 제대로 동작하지 않을 수도 있습니다. 따라서 가능하면 signal을 쓰지 않도록 노력해보기 바랍니다. 그래도 꼭 signal을 써야만 한다면...

pthread_sigmask()를 써서 thread당 독립적으로 동작하는 signal mask를 등록하면 됩니다. 즉 signal을 받고자 하는 thread를 제외한 나머지 thread들에서 해당 signal을 블럭시키면 됩니다. (race condition을 방지하기 위해) thread를 처음 만들 때 자식 thread는 부모 thread로부터 signal mask를 상속받기 때문에, 자식 thread를 여러개 만들기 전에 먼저 블럭시킨다음 thread들을 만들고 나서 원하는 thread에서 unblock시키는 방법을 쓰는 것이 좋습니다.

노파심에서 말하지만 single threaded program에서 같은 목적으로 쓰는 sigprocmask()는 multi threaded program에서 쓰면 안됩니다.

자세한 것은 Programming with POSIX Threads에 잘 나와 있으니 참고하기 바랍니다.

타임아웃.. 예외없이 SELECT로 해결하시면 될듯합니다. 다만 CONN

타임아웃.. 예외없이 SELECT로 해결하시면 될듯합니다. 다만 CONNECT시 응답이 늦으면 완전히 블락이 걸리는 특성이 있으니 이전에 넌블락 모드로 설정하신후에 마지막에 이것을 해제해주시면 될듯합니다.
int status;

socket(); // 접속용 소켓 오픈
fcntl(); // 넌블락으로 셋
status = connect();

이부분에서 기종에 따라 리턴값이 달라집니다. 보통은 0보다 작으면서 PROGRESS메시지를 리턴하는데 이때 루프에 들어가 select 해주시면 됩니다.
while()
select(); 이부분은 쓰기검사를 하시고요.
connect();

대충 생각나는데로 해보았는데 저의 경험으로는 단지 리눅스용으로 하실거라면 이정도만 해도 잘 돌아 갑니다. 그런데 다른 기종에 포팅을 생각하시면 에러 리턴을 조금더 세밀하게 맞추셔야 할겁니다. 제가 LINUX/AIX/HPUX/SOLARIS 이렇게 맞추었는데 조금씩 다르더라구요.

시간이 되시면 모자익 소스를 한번 보시는게 어떠실런지요. 이거를 조금 수정하셔서 하시는게 좋을듯 싶습니다. 잠깐만요. 주소를 한번 찾아 보구요. 지금 찾았습니다.

아랫부분을 조금 수정하셔서 사용하시는게 어떠실런지요.

http://archive.ncsa.uiuc.edu/SDG/Software/XMosaic/

PUBLIC int HTDoConnect (char *url, char *protocol, int default_port, int *s)
{
  struct sockaddr_in soc_address;
  struct sockaddr_in *sin = &soc_address;
  int status;

  /* Set up defaults: */
  sin->sin_family = AF_INET;
  sin->sin_port = htons(default_port);
  
  /* Get node name and optional port number: */
  {
    char line[256];
    char *p1 = HTParse(url, "", PARSE_HOST);
    int status;

    sprintf (line, "Looking up %s.", p1);
    HTProgress (line);

    status = HTParseInet(sin, p1);
    if (status) 
      {
        sprintf (line, "Unable to locate remote host %s.", p1);
        HTProgress(line);
        free (p1);
        return HT_NO_DATA;
      }

    sprintf (line, "Making %s connection to %s.", protocol, p1);
    HTProgress (line);
    free (p1);
  }

  /* Now, let's get a socket set up from the server for the data: */      
  *s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

#ifdef SOCKS
  /* SOCKS can't yet deal with non-blocking connect request */
  HTClearActiveIcon();
  status = Rconnect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));
  if ((status == 0) && (strcmp(protocol, "FTP") == 0))
     SOCKS_ftpsrv.s_addr = soc_address.sin_addr.s_addr;
  {
    int intr;
    intr = HTCheckActiveIcon(1);
    if (intr)
      {
        if (TRACE)
          fprintf (stderr, "*** INTERRUPTED in middle of connect.\n");
        status = HT_INTERRUPTED;
        errno = EINTR;
      }
  }
  return status;
#else /* SOCKS not defined */


  /*
   * Make the socket non-blocking, so the connect can be canceled.
   * This means that when we issue the connect we should NOT
   * have to wait for the accept on the other end.
   */
  {
    int ret;
    int val = 1;
    char line[256];
    
    ret = ioctl(*s, FIONBIO, &val);
    if (ret == -1)
      {
        sprintf (line, "Could not make connection non-blocking.");
        HTProgress(line);
      }
  }
  HTClearActiveIcon();

  /*
   * Issue the connect.  Since the server can't do an instantaneous accept
   * and we are non-blocking, this will almost certainly return a negative
   * status.
   */
  status = connect(*s, (struct sockaddr*)&soc_address, sizeof(soc_address));

  /*
   * According to the Sun man page for connect:
   *     EINPROGRESS         The socket is non-blocking and the  con-
   *                         nection cannot be completed immediately.
   *                         It is possible to select(2) for  comple-
   *                         tion  by  selecting the socket for writ-
   *                         ing.
   * According to the Motorola SVR4 man page for connect:
   *     EAGAIN              The socket is non-blocking and the  con-
   *                         nection cannot be completed immediately.
   *                         It is possible to select for  completion
   *                         by  selecting  the  socket  for writing.
   *                         However, this is only  possible  if  the
   *                         socket  STREAMS  module  is  the topmost
   *                         module on  the  protocol  stack  with  a
   *                         write  service  procedure.  This will be
   *                         the normal case.
   */
#ifdef SVR4
  if ((status < 0) && ((errno == EINPROGRESS)||(errno == EAGAIN)))
#else
  if ((status < 0) && (errno == EINPROGRESS))
#endif /* SVR4 */
    {
      struct timeval timeout;
      int ret;

      ret = 0;
      while (ret <= 0)
	{
          fd_set writefds;
          int intr;
          
          FD_ZERO(&writefds);
          FD_SET(*s, &writefds);

	  /* linux (and some other os's, I think) clear timeout... 
	     let's reset it every time. bjs */
	  timeout.tv_sec = 0;
	  timeout.tv_usec = 100000;

#ifdef __hpux
          ret = select(FD_SETSIZE, NULL, (int *)&writefds, NULL, &timeout);
#else
          ret = select(FD_SETSIZE, NULL, &writefds, NULL, &timeout);
#endif
	  /*
	   * Again according to the Sun and Motorola man pagse for connect:
           *     EALREADY            The socket is non-blocking and a  previ-
           *                         ous  connection attempt has not yet been
           *                         completed.
           * Thus if the errno is NOT EALREADY we have a real error, and
	   * should break out here and return that error.
           * Otherwise if it is EALREADY keep on trying to complete the
	   * connection.
	   */
          if ((ret < 0)&&(errno != EALREADY))
            {
              status = ret;
              break;
            }
          else if (ret > 0)
            {
	      /*
	       * Extra check here for connection success, if we try to connect
	       * again, and get EISCONN, it means we have a successful
	       * connection.
	       */
              status = connect(*s, (struct sockaddr*)&soc_address,
                               sizeof(soc_address));
              if ((status < 0)&&(errno == EISCONN))
                {
                  status = 0;
                }
              break;
            }
	  /*
	   * The select says we aren't ready yet.
	   * Try to connect again to make sure.  If we don't get EALREADY
	   * or EISCONN, something has gone wrong.  Break out and report it.
	   * For some reason SVR4 returns EAGAIN here instead of EALREADY,
	   * even though the man page says it should be EALREADY.
	   */
          else
            {
              status = connect(*s, (struct sockaddr*)&soc_address,
                               sizeof(soc_address));
#ifdef SVR4
              if ((status < 0)&&(errno != EALREADY)&&(errno != EAGAIN)&&
			(errno != EISCONN))
#else
              if ((status < 0)&&(errno != EALREADY)&&(errno != EISCONN))
#endif /* SVR4 */
                {
                  break;
                }
            }
          intr = HTCheckActiveIcon(1);
          if (intr)
            {
              if (TRACE)
                fprintf (stderr, "*** INTERRUPTED in middle of connect.\n");
              status = HT_INTERRUPTED;
              errno = EINTR;
              break;
            }
	}
    }

  /*
   * Make the socket blocking again on good connect
   */
  if (status >= 0)
    {
      int ret;
      int val = 0;
      char line[256];
      
      ret = ioctl(*s, FIONBIO, &val);
      if (ret == -1)
	{
          sprintf (line, "Could not restore socket to blocking.");
          HTProgress(line);
	}
    }
  /*
   * Else the connect attempt failed or was interrupted.
   * so close up the socket.
   */
  else
    {
	close(*s);
    }

  return status;
#endif /* #ifdef SOCKS */
}

alonecrow의 아바타

답변감사합니다... 찾아보니 자료가 몇개 더 있더군요... ^^

찾아보니 자료가 더 있어 소스한개를 더 올립니다.
UNIX Networking programming 에 있는 소스입니다.
두가지 모두 테스트 해보았는데 모두잘되더군요...

int connect_nonb(int sockfd, char *strIP)
{
	int len=0, status, flags;
	struct sockaddr_in address;
	fd_set rset, wset;
	struct timeval tval;

	address.sin_family = AF_INET;
	address.sin_addr.s_addr = inet_addr(strIP);
	address.sin_port = htons(SMTP_PORT);

	len = sizeof(address);

#ifdef TEST
	printf("Connect IP:%s\n", strIP);
#endif

	// Non Block 모드로 만든다.
	flags = fcntl(sockfd, F_GETFL, 0);
	if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
#ifdef TEST
		switch (errno) {
			case EACCES: fprintf(stderr,"EACCES\n"); break;
			case EAGAIN: fprintf(stderr,"EAGAIN\n"); break;
			case EBADF:  fprintf(stderr,"EBADF\n"); break;
			case EDEADLK:fprintf(stderr,"EDEADLK\n"); break;
			case EFAULT: fprintf(stderr,"EFAULT\n"); break;
			case EINTR:  fprintf(stderr,"EINTR\n"); break;
			case EINVAL: fprintf(stderr,"EINVAL\n"); break;
			case EMFILE: fprintf(stderr,"EMFILE\n"); break;
			case ENOLCK: fprintf(stderr,"ENOLCK\n"); break;
			case EPERM:  fprintf(stderr,"EPERM\n"); break;
		}
#endif
		return -1;
	}

	status = connect(sockfd, (struct sockaddr *)&address, len);

	if ((status < 0) && (errno == EINPROGRESS))
	{
#ifdef TEST
		fprintf(stderr, "errno: %d\n", errno);

		switch (errno) {
			case EBADF:		fprintf(stderr,"EBADF\n"); break;
			case EFAULT:            fprintf(stderr,"EFAULT\n"); break;
			case ENOTSOCK:          fprintf(stderr,"ENOTSOCK\n"); break;
			case EISCONN:           fprintf(stderr,"EISCONN\n"); break;
			case ECONNREFUSED:      fprintf(stderr,"ECONNREFUSED\n"); break;
			case ETIMEDOUT:         fprintf(stderr,"ETIMEDOUT\n"); break;
			case ENETUNREACH:       fprintf(stderr,"ENETUNREACH\n"); break;
			case EADDRINUSE:        fprintf(stderr,"EADDRINUSE\n"); break;
			case EINPROGRESS:       fprintf(stderr,"EINPROGRESS\n"); break;
			case EALREADY:          fprintf(stderr,"EALREADY\n"); break;
			case EAGAIN:            fprintf(stderr,"EAGAIN\n"); break;
			case EAFNOSUPPORT:      fprintf(stderr,"EAFNOSUPPORT\n"); break;
			case EACCES:            fprintf(stderr,"EACCES\n"); break;
			case EPERM:             fprintf(stderr,"EPERM\n"); break;
			default:		fprintf(stderr,"예외\n"); break;
		}
#endif
		return -1;
	}

	if (status == 0) goto done;

	FD_ZERO (&rset);
	FD_SET (sockfd, &rset);
	wset = rset;

	tval.tv_sec = TIMEOUT;
	tval.tv_usec = 0;

	if ((status = select(sockfd + 1, &rset, &wset, NULL, TIMEOUT ? & tval : NULL)) == 0) {
		close(sockfd);
		errno = ETIMEDOUT;
		return (-1);
	}

	if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
		len = sizeof(errno);
		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &errno, &len) < 0)
			return (-1);
	} else {
		fprintf(stderr, "SELECT error: sockfd not set");
		return (-1);
	}


done:
	fcntl(sockfd, F_SETFL, flags);

	if (errno) {
		close(sockfd);
		return (-1);
	}

	return (0);
} 

alarm signal을 이용하시면 간단한데...[code:1]

alarm signal을 이용하시면 간단한데...

signal(SIGALRM, socket_timeout);
alarm(1);
state = connect(sockfd, (struct sockaddr *)&address, len); 
if (state < 0) {
	alarm(0);
	return(-1);
}
alarm(0);

....
나중에 socket_timeout 함수만 구현해주면 끝나염..

이렇게 하면 간단하게 구현할 수 있습니다~~~ 참조하세요~

fanuk의 아바타

[quote="은빛연어"]alarm signal을 이용하시면 간단한데..

은빛연어 wrote:
alarm signal을 이용하시면 간단한데...

signal(SIGALRM, socket_timeout);
alarm(1);
state = connect(sockfd, (struct sockaddr *)&address, len); 
if (state < 0) {
	alarm(0);
	return(-1);
}
alarm(0);

....
나중에 socket_timeout 함수만 구현해주면 끝나염..

이렇게 하면 간단하게 구현할 수 있습니다~~~ 참조하세요~

아.. 이거 좋군요..;; recv()에 대해서도 똑같이 적용할 수 있나요? 있을거 같긴 한데.. 흠..