기본 콘텐츠로 건너뛰기

2015.08: 3D Printed Rototic Hand and Its Remote Control - (리눅스/윈도우즈 소켓 프로그래밍)

립모션을 사용한 로봇손 제어 프로젝트에서 활용하기 위해 소켓 프로그래밍을 구현하게 되었다. 사용자 손 값을 받는 쪽은 윈도우즈 상에 구현되어있고, 로봇 손 하드웨어 제어 부분은 리눅스에 구현되어 있다. 소켓프로그래밍도 기억이 잘 안나고 윈도우즈와 리눅스 사이 통신이 어떻게 되는지 막막했지만, 여러 샘플들이 많이 나와있어서 정리해봤다.

리눅스 서버
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

void error( char *msg ) {
  perror(  msg );
  exit(1);
}


int main(int argc, char *argv[]) {
     int sockfd, newsockfd, portno = 27015, clilen;        ///socket
     char buffer[512];
     struct sockaddr_in serv_addr, cli_addr;     
     int n;
     int iter=0;
     int data;
     int rBuffer[512];
     int sBuffer[512];
     int *temp;
     int length;

     printf( "using port #%d\n", portno );
 
     sockfd = socket(AF_INET, SOCK_STREAM, 0);            ///socket
     if (sockfd < 0)
         error( const_cast<char *>("ERROR opening socket") );
     bzero((char *) &serv_addr, sizeof(serv_addr));

     serv_addr.sin_family = AF_INET;                    ///socket
     serv_addr.sin_addr.s_addr = INADDR_ANY;            ///bind
     serv_addr.sin_port = htons( portno );                ///bind
     if (bind(sockfd, (struct sockaddr *) &serv_addr,    ///bind
              sizeof(serv_addr)) < 0)
       error( const_cast<char *>( "ERROR on binding" ) );
     if (listen(sockfd,5) < 0){                            ///listen
        error(const_cast<char *>( "ERROR on listening"));
     };
     clilen = sizeof(cli_addr);                            ///Accept

     //--- infinite wait on a connection ---
     while ( 1 ) {
        printf( "waiting for new client...\n" );
        if ( ( newsockfd = accept( sockfd, (struct sockaddr *) &cli_addr, (socklen_t*) &clilen) ) < 0 )
            error( const_cast<char *>("ERROR on accept") );
        printf( "opened new communication with client\n" );    
     
        while ( 1 ) {
             length = 0;
             temp = rBuffer;
           
             printf( "received    :");
             while((n = read(newsockfd, temp, sizeof(sBuffer[1]))) > 0){
                 rBuffer[length] = *temp;           
             
                 sBuffer[length] = *temp;
                 printf( "%d ", rBuffer[length]);
         
                 if(length == 6) break;
                 temp++;
                 length++;
            }             
            printf( "\n");
            write(newsockfd, sBuffer, 7*sizeof(sBuffer[1]));           
            printf( "sending back:");
             for(int i=0; i<7; i++){
                 printf( "%d ", sBuffer[i]);
             }
             printf( "\n");
           
             iter++;
        }
        close( newsockfd );    break;///socket

     }
     return 0;
}

리눅스 클라이언트
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

void error(char *msg) {
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
    int sockfd, portno = 27015, n;
    char serverIp[] = "10.92.64.17";
    struct sockaddr_in serv_addr;                                ///socket
    struct hostent *server;
    char sBuffer[] = {1, 2, 3, 4, 5, 6, 7};
    int length = 0;
    int iter=0;
    char rBuffer[512];
    char *temp;

    if (argc < 3) {
      // error( const_cast<char *>( "usage myClient2 hostname port\n" ) );
      printf( "contacting %s on port %d\n", serverIp, portno );
      // exit(0);
    }
    if ( ( sockfd = socket(AF_INET, SOCK_STREAM, 0) ) < 0 )        ///socket
        error( const_cast<char *>( "ERROR opening socket") );

    if ( ( server = gethostbyname( serverIp ) ) == NULL )
        error( const_cast<char *>("ERROR, no such host\n") );
 
    bzero( (char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;                                ///socket
    bcopy( (char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portno);                            ///bind
    if ( connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        error( const_cast<char *>( "ERROR connecting") );
    while(1){
     
        length = sizeof(sBuffer)/sizeof(*sBuffer);
         
          //sendData( sockfd, n );
          sBuffer[length]='\n';
          write(sockfd, sBuffer,length+1);
          printf("send :   ");
          for( int i=0; i<7; i++){
              printf("%d ",sBuffer[i]);
          }
          printf("\n");
       
          if((n =  read(sockfd,rBuffer,7)) < 0)
              break;
       
          rBuffer[7] = '\n';
       
          printf("respond: ");
          for(int i=0; i<7; i++){
                printf( "%d ", rBuffer[i]);
                sBuffer[i] = rBuffer[i];
            }
            printf("\n");
     
        if(iter==3)     break;
        iter++;     
    }
    close( sockfd );
    return 0;
}

윈도우즈 서버
#undef UNICODE

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>

// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

int __cdecl main(void)
{
    WSADATA wsaData;
    int iResult;

    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET ClientSocket = INVALID_SOCKET;

    struct addrinfo *result = NULL;
    struct addrinfo hints;

    int iSendResult;
    char recvbuf[DEFAULT_BUFLEN];
    int recvbuflen = DEFAULT_BUFLEN;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Create a SOCKET for connecting to server
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    // Setup the TCP listening socket
    iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    freeaddrinfo(result);

    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("listen failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // Accept a client socket
    ClientSocket = accept(ListenSocket, NULL, NULL);
    if (ClientSocket == INVALID_SOCKET) {
        printf("accept failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // No longer need server socket
    closesocket(ListenSocket);

    // Receive until the peer shuts down the connection
    do {

        iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0) {
            printf("Bytes received: %d\n", iResult);
            printf("%s\n", &recvbuf);

            // Echo the buffer back to the sender
            iSendResult = send(ClientSocket, recvbuf, iResult, 0);
            if (iSendResult == SOCKET_ERROR) {
                printf("send failed with error: %d\n", WSAGetLastError());
                closesocket(ClientSocket);
                WSACleanup();
                return 1;
            }
            printf("Bytes sent: %d\n", iSendResult);
        }
        else if (iResult == 0)
            printf("Connection closing...\n");
        else  {
            printf("recv failed with error: %d\n", WSAGetLastError());
            closesocket(ClientSocket);
            WSACleanup();
            return 1;
        }

    } while (iResult > 0);

    // shutdown the connection since we're done
    iResult = shutdown(ClientSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return 1;
    }

    // cleanup
    closesocket(ClientSocket);
    WSACleanup();

    return 0;
}

윈도우즈 클라이언트
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>


// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")


#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

int __cdecl main(int argc, char **argv)
{
    WSADATA wsaData;                                        ///socket
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
        *ptr = NULL,
        hints;
    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;

    // Validate the parameters
    if (argc != 2) {
        printf("usage: %s server-name\n", argv[0]);
        return 1;
    }

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);            ///socket
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Attempt to connect to an address until one succeeds
    for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {

        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,    ///socket
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("socket failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return 1;
        }

        // Connect to server.
        iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
 

    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    // Receive until the peer closes the connection
    do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0)
            printf("Bytes received: %d\n", iResult);
        else if (iResult == 0)
            printf("Connection closed\n");
        else
            printf("recv failed with error: %d\n", WSAGetLastError());

    } while (iResult > 0);

    // cleanup
    closesocket(ConnectSocket);                    ///socket
    WSACleanup();                                ///socket

    return 0;
}

<MSDN Sample>
https://msdn.microsoft.com/en-us/library/windows/desktop/ms737889%28v=vs.85%29.aspx

댓글

이 블로그의 인기 게시물

공부: Multiple View Geometry (3)Cont.

Multiple View Geometry Study Note 2. Projective Geometry and Transformations of 2D (Cont.3) 지난번 MVG(3)에서는 2D geometry에서 affine properties의 복원에 대해서 공부했습니다. 이번에는 metric properties의 복원에 대해 공부할 것 입니다. 지난 공부에서 배웠듯이 metric properties에는 angle, length ratio가 있습니다. 이 성분들을 복원하기 위해 우리는 conic dual to circular points라는 개념을 사용합니다. 그럼 circular points부터 시작하겠습니다. WIKI : circular points at infinity? absolute points라고도 불리는 circular points는 similarity transform에 불변하는 점입니다. I,J로 표시하는데 복소수를 사용하는 저런 좌표를 canonical coordinates라고 하고 I와J는 서로 켤레 복소수 임을 알 수 있습니다. 이 두 점이 similarity transform에 불변하는 것은 왼쪽 슬라이드 두번째 식을 보면 알 수 있습니다. 변환 결과 homogeneous 좌표 모든부분에 같은 실수가 곱해지므로, 결과적으로 similarity transform에 불변함을 증명할 수 있습니다. 'circular points at infinity lie on the complexification of every real circle.' 코닉이 원이 되려면 코닉 기본식에서 a=c, b=0을 만족해합니다. complexification(infinity와 관련?)이기 때문에 x3=0인 것 같습니다. 그럼 결국 오른쪽의 코닉 식에서 만족하는 점은 circular points at infinity인 I와 J 입니다. 또한 I와 J를 외적하면 (0,0,i)인 복소수 곱의 line

공부: Multiple View Geometry (1)

Multiple View Geometry Study Note 1. Introduction 연구실에서 MVG 세미나를 진행하여, 참석하게 되었다. 블로그를 시작하면서 내 공부를 정리하는 공간으로 활용해 보고 싶었는데 이번 기회에 제대로 시작하려고 한다. 그림 1. 다시점에서 3D 객체의 사영(projection) 위 그림 1.을 인식하는 것 부터 관련 공부가 펼쳐진다. 실세계의 3D 물체가 카메라 등의 2D 영상으로 매핑되는 것, 관련된 카메라 파라미터, 여러 수학적 설명 방법들을 이해한다. 그리고 더 나아가서 공학적으로 사용한다. 3D가 2D로 매핑되는 것과 반대로, 2D 영상과 시점의 정보를 사용하여 3D 객체를 재현할 수도 있을 것이다. 3D reconstruction 연구에는 다양한 접근 방법이 있다. 하지만 모든 방법에서 가장 기본이 되는 것은 MVG인 것 같다. 관련된 영상들을 몇개 찾아보니 재미있을 것 같지만 굉장히 어렵다고 한다. 앞으로 공부가 기대된다.   3D models from 2D video - automatically Researchers of Computer Vision and Geometry lab Transforming a 2D image into 3D Researchers of Carnegie Mellon University Mathematical  : 3D 컴퓨터 비전 위한 기하학 Seminar study :   D. Kim, MVG Seminar, 2012 winter @IPIS\ Reference book : "Multiple View Geometry in Computer Vision" by Richard Hartley Multiple View Geometry in Computer Vision Richard Hartley |   Cambridge University Press |  2004.02.01  |  672p  |

공부: Multiple View Geometry (3)

Multiple View Geometry Study Note 2. Projective Geometry and Transformations of 2D (Cont.2) 첫번째로 맡게된 발표에서 다룬 내용은 Projective transformation 된 영상에서, 원영상의 Affine properties와 Meric properties를 회복시켜서 원영상의 모양을 복원하는 주제입니다.  이전의 개념들을 사용하여 실질적인 목적을 수행하는 내용으로 중요한 내용입니다. 발표준비를 하면서 몇일 밤을 새면서 공부했는데, 공부하면 할 수록 너무 재밌는 내용입니다.  이전에 머릿 속에 대강 있던 이차원 공간상의 여러 기하학적 개념을 구체화 하고,  수학이란 툴을 사용해서 실제 영상에 적용하는 이론을 배웠습니다.  여태 살아오면서 가장 열심히 공부했던 것 같습니다.  그럼, 내가 준비한 발표자료와 간단한 설명을 정리해보겠습니다.  따끈따근한 오늘 발표의 포스팅입니다. 이 발표에서는 Projective Transform된 이차원 영상의 특성과 그것을 복원하는 복원할 때 어떤 접근 방법들이 있는지 알아보겠습니다. Projective Transform은 카메라, 극단적으로 우리 시각에서도 항상 일어나는 개념으로 모두가 잘 알고 있을 것으로 생각됩니다.  이제 시작할 이야기를 이해 하시려면 지난번 MVG(2)의 개념들을 알고 있어야합니다.  영상의 기하학적인 성질은 크게 두가지로 나눌 수 있습니다. 첫번째로 Affine properties는 선의 평행성, 평행선 끼리의 길이 비율 입니다. Affine properties는 line at infinity와 밀접하게 연관하여 결정되는 것으로, line at infinity를 실선으로 매핑시키는 Projective transform 성분중 Hp으로 특성이 왜곡됩니다. 두번째로 Metirc properties는 선과 선 사이의 각도와 선 끼리의 길이비율 입니다.