블로그 이미지
devtang
Instagram : @taebr0 devtaehyeong@gmail.com

calendar

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

Notice

2020. 3. 10. 14:41 개인 프로젝트

개인 프로젝트를 위해 저에게 필요한 단방향 소켓 통신방식을 만들어 봤습니다.

 

 

기본적인 세팅 구조

 

우선 라즈베리파이에 data.txt라는 텍스트 파일에 Random한 시간과 내용을 실시간으로 적게 되면,

윈도우에서 실시간으로 받은 문장을 server.txt라고 만든 텍스트 파일에 실시간으로 적어주는 방식입니다.

저번 출입알림시스템 때 이용해봤지만 리눅스-리눅스 환경의 소켓 통신이라 이번에는 서버코드를 약간 수정했습니다.

 

data.txt 파일에 ABCD를 적어서 저장하는 순간 윈도우내 지정된 server.txt 파일에 문자가 저장됩니다.

소켓으로 실시간 메모장을 열고 확인해야 하기 때문에 조금 비효율적이지만 

제가 배운 선에서 최대한 저한테 이용하기 편리하게 만들어놨습니다.

 

Windows 10 에서 구동한 소스 코드입니다. (Server)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib")
#include <WinSock2.h>
#include <windows.h>


#define  BUF_SIZE   1024
void ErrorHandling(char *message);
int main(int argc, char *argv[])

{
   FILE *fp;
   WSADATA wsaData;
   SOCKET hServSock, hClntSock;
   SOCKADDR_IN servAddr, clntAddr;
   char message[BUF_SIZE];
   char write_memo[BUF_SIZE] = { 0, };
   int str_len, j;
   int szClntAddr;

   if (argc != 2)
   {
      printf("Usage:%s <port>\n", argv[0]);
      exit(1);
   }



   if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) //소켓 라이브러리 초기화
      ErrorHandling("WSAStartup() error!");

   hServSock = socket(PF_INET, SOCK_STREAM, 0); //소켓생성

   if (hServSock == INVALID_SOCKET)
      ErrorHandling("socket() error");

   memset(&servAddr, 0, sizeof(servAddr));
   servAddr.sin_family = AF_INET;
   servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
   servAddr.sin_port = htons(atoi(argv[1]));

   if (bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) //IP주소와 PORT 번호 할당
      ErrorHandling("bind() error");

   if (listen(hServSock, 5) == SOCKET_ERROR) //listen 소켓을 서버 소켓으로 완성
      ErrorHandling("listen() error");


   szClntAddr = sizeof(clntAddr);
   hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &szClntAddr); // accept함수 호출
   if (hClntSock == INVALID_SOCKET)
      ErrorHandling("accept() error");

   while (1)
   {
      str_len=recv(hClntSock, message, sizeof(message)-1, 0); //클라이언트 메세지를 받음
      if (strcmp(write_memo, message) == 0) // *참고
         continue;
      else {
         fp = fopen("C:\\**TXT파일의위치**", "w"); //fopen함수 이용하여 메모장 쓰기모드로 열기
         fwrite(message, strlen(message), 1, fp); // 받은 메세지를 메모장에 쓰기
         fclose(fp); // 메모장을 닫는다.
         strcpy(write_memo, message); // *받은 메세지를 write_memo 변수에 복사해놓음(계속 쓰는것을 방지)
         printf("Message from Client : %s", message); //받은 메세지를 표시
      }
      for (j = 0; j < 100; j++) {
         message[j] = 0; //100글자까지 초기화
      }
         
   }
   closesocket(hClntSock);
   closesocket(hServSock);
   WSACleanup();
   return 0;
}

void ErrorHandling(char *message)
{
   fputs(message, stderr);
   fputc('\n', stderr);
   exit(1);
}

받은 message를 write_memo 라는 변수를 만들어서 복사해준 이유는 

라즈베리파이에서 예를들어 'ABCD'를 입력하면 한번만 보내는것이 아니라 무한적으로 ABCD를 계속 보내게 됩니다.

따라서 write_memo에 전에받았던 'ABCD'를 저장해놓으면 다음 while 루프때 문자가 바뀌지않으면

다음 문장을 입력받기 전까지 대기하게 할 수 있어서 만들어놨습니다.

 

아래는 RaspberryPi에서 구동한 소스 코드입니다.(Client)

 

#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  BUF_SIZE   1024
void error_handling(char *message);

int main( int argc, char *argv[])
{
   char send_socket[BUF_SIZE]= {0,};
   int sock;
   char message[BUF_SIZE];
   struct sockaddr_in serv_adr;
   FILE *fp;
   if(argc != 3) {
      printf("Usage : %s <IP> <PORT>\n", argv[0]);
      exit(1);
   }
   
   sock= socket( PF_INET, SOCK_STREAM, 0);
   if( -1 ==sock)
      error_handling("socket() error");

   memset( &serv_adr, 0, sizeof( serv_adr));
   serv_adr.sin_family     = AF_INET;
   serv_adr.sin_addr.s_addr= inet_addr(argv[1]);
   serv_adr.sin_port       = htons(atoi(argv[2]));
  

   if( -1 == connect(sock, (struct sockaddr*)&serv_adr, sizeof( serv_adr) ) )
   {
      printf( "접속 실패\n");
      exit( 1);
   }
   
   
   while(1){
   
      fp = fopen("**TXT파일 위치**","r"); // 읽기 모드로 TXT파일을 열기
      fscanf(fp, "%s",message); // TXT파일내 문장을 읽기
      //printf("MES : %s",message);
      fclose(fp);
      if(strcmp(message,send_socket)==0)
      {
    	continue;
      }
      else{
    strcpy(send_socket,message);
    printf("SEND : %s\n", send_socket);
    write(sock,message,sizeof(message)-1); // 서버로 message 전송
    }
      
      
   }
   close(sock);
   return 0;
}

void error_handling(char *message)
{
   fputs(message,stderr);
   fputc('\n',stderr);
   exit(1);
}

 

여기도 마찬가지로 제가 쓰던 코드라 조금 난잡할수도 있습니다. 위와 같은 방식으로 send_socket이라는 변수에 message를 저장시켜 문장이 변하지 않으면 계속 while 루프를 돌도록 구현했습니다.

 

아래는 프로그램 구현 동영상입니다.

 

 

 

참고도서 : 윤성우의 열혈 TCP/IP 소켓 프로그래밍

 

====== 오렌지 미디어 ======

             목록 서버1   서버2 강의시간 강의교안  PART 01 네트워크 프로그래밍의 시작    Chapter 01 네트워크 프로그래밍과 소켓의 이해        01-1. 네트워크 프로그래밍과 소켓의 이해① 27:43        01-1. 네트워크 프로그래밍과 소켓의 이해② 07:58        01-1. 네트워크 프로그래밍과 소켓의 이해③ 12:52        01-2. 리눅스 기반 파일 조작하기 27:27        01-3.

www.orentec.co.kr

 

posted by devtang