블로그 이미지
송시혁

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

Tag

Recent Post

Recent Comment

Recent Trackback

Archive

2018. 6. 17. 01:51 네트워크/vmware 실습

vmware find to connect to error와는 다른거다. 이거는 vmware server 서비스를 중지가 되어 생긴 문제이다.


아래 실행창에서 다음과 같이 입력한다.


vmware workstation server를 찾아서 우클릭한다.


시작하면 된다. 필자는 이미 시작했으므로 비활성화 되어있는 것이다. 


posted by 송시혁
2013. 7. 15. 14:30 네트워크/vmware 실습



7월 12일 소스에서 L2list배열을 추가한다. 그리고 L2ip.c의 함수에서 스위치문에 내용을 긁어온다.





















L3tcp.c 함수




posted by 송시혁
2013. 7. 12. 19:29 네트워크/vmware 실습



#include "ethernet.h"
#include "hexaview.h"

//  write (1, "\033[1;1H\033[2J", 10);//화면 지우는 것. 

void hexaview(unsigned char *ucP, unsigned int isize);

typedef struct _L1_map
{
  unsigned int uiType;
  int (*L1func)(void *);
  
}L1_map;
//전역변수로 typedef struct 구조체 정의.

L1_map L1list[]={
                          {ETHERTYPE_PUP,     0},
                          {ETHERTYPE_IP,      L2_IP},
                          {ETHERTYPE_ARP,     0},
                          {ETHERTYPE_REVARP,  0},
                          {0xFFFFFFFF      ,  0}              
      
                      };
// 전역변수로 구조체 L1list선언.


int main()
{
  int iSock;
  int iRet;
  struct ifreq stIF;  //
  unsigned char ucBuff[1500];
  struct sockaddr_in stPkat_Info;
  unsigned int uiLen=sizeof(stPkat_Info);
  L1_map *stpL1;
  int ipProto;
  
  iSock=socket(AF_INET, SOCK_PACKET, ntohs(ETH_P_ALL));//소켓 생성. 
  if(0>iSock)
  {
    fprintf(stderr, "error");
    return 0;
  }
//위 if문은 에러시 화면에 error를 찍고 프로그램 종료.

  strcpy(stIF.ifr_name, "eth0" );//문자열 eth0를 stIF.ifr_name에 대입.(랜카드, 랜번호)
  
  iRet=ioctl(iSock, SIOCGIFFLAGS, &stIF);  //ioctl()함수 사용.
//첫 번째 인자는 소켓번호, 두번재 인자는 , 3번째 인자는 크기.
  
  if(0>iRet)//에러처리
  {
    fprintf(stderr, "error");
    close(iSock);
    return 0;
  }
  stIF.ifr_flags= stIF.ifr_flags|IFF_PROMISC;//IFF_PROMISC는 랜카드를 PROMISC모드로 설정한다.

  iRet=ioctl(iSock, SIOCSIFFLAGS, &stIF);  //소켓을 설정한다.

  if(0>iRet)
  {
    fprintf(stderr, "error");
    close(iSock);
    return 0;
  }

  iRet=recvfrom(iSock, ucBuff, 15000, (struct sockaddr *)&stPkat_Info , &uiLen);
 /*   
데이터를 수신하는 함수
1.소켓
2.데이터를 저장하는 버퍼
3.데이터를 저장하는 버퍼의 크기를 지정.
4.제어 플래그, 대부분의 경우 0으로 설정한다.
5.송신자의 주소, 구조체. 이 구조체의 반환영에 따라 struct sockaddr형으로 캐스팅한다. 포인터이기 때문에 인자에
  주소를 넣어야 한다.
6. 자료형이 포인터이기 때문에 주소로 받아야하며, 송신자 주소의 크기가 되겠다.
*/

  ipProto=L1_ethernet(ucBuff);//L1_ethernet(ucBuff)함수를 호출한다. 반환형은 int형. ipProto에 넣는다.
                                      //함수의 설명은 아래 소스를 참조. 인자는 void형 포인터. 송신된 데이터가 들어있는
                                     // ucBuff를 인자로 넣는다.


  stpL1=L1list;         //전역변수 구조체형 L1list배열을 구조체형 포인터에 대입. 배열이름은 주소이기때문에 
                           //포인터에 대입이 가능한다.
//아래 while문이 실행됨으로서 L1list안에 내용들이 출력이 된다. 

  while(1)
  {
    if(iProto==(stpL1->uiType)) //iProto와 stpL1->uiType과 같으면, 정지. uiType은 전역변수 unsigned int형 구조체의 멤버.
    {                                    
      break;
    }
    if(0xFFFFFFFF==(stpL1->uiType))//L1list의 배열의 끝으로 마찬가지로 while문에 종료조건이다.
    {
      break;  

    }
    ++stpL1;   //포인터를 한 칸 이동시키면, 가르키는 주소도 한 칸 이동된다. 처음에는 L1list[0]을  가르키다
                  // 1증가하면 다음주소인 L1list[1]을 가르킨다.

  }

  if(0!=stpL1->L1func)
  {
    (stpL1->L1func)(ucBuff+14);//

  }


  hexaview(ucBuff,iRet);  //헥사뷰 함수 호출.

  close(iSock);  
  return 0;
}


void hexaview(unsigned char *ucP, unsigned int isize)
{
  int iCnt;
  int iLoop;

  printf("---------------------------------------"
      "----------------------------------\n");
  printf("address                     Hexa                              ASCII\n");
  printf("         ");
  for(iCnt=0; iCnt<=15; iCnt= iCnt +1)
  {
    printf("%02X ", iCnt);
  }


  putchar('\n');


  printf("---------------------------------------"
      "----------------------------------\n");

  if(0==isize%16)
  {
    isize = isize/16;
  }
  else
  {
    isize = (isize/16)+1;
  }
  for(iLoop=0;iLoop< isize;iLoop= iLoop+1)  
  {
    printf("%08X ", ucP);

    for(iCnt=0;iCnt<=15;iCnt=iCnt +1)
    {  
      printf("%02X ", *(ucP+iCnt));
    }  

    for(iCnt=0; iCnt<=15; iCnt= iCnt +1)
    {


      if(0==*(ucP+iCnt))
      {  
        printf(".");
      }
      else if(*(ucP+iCnt)<32)
      {
        printf(".");
      }
      else if(*(ucP+iCnt)>127)
      {
        printf(".");
      }
      else
      {
        printf("%c",  *(ucP+iCnt));
      }  
    }
    putchar('\n');
    ucP= ucP+16;
  }

  return;

}







L1_ethernet.c 함수

//패킷을 건져올리는 함수.

#include "ethernet.h"

int L1_ethernet(void *vp)
{
  struct ether_header *stEth=(struct ether_header *)vp;
    
  //printf("-----%02s\n", ether_ntoa ((struct ether_addr *)stEth->ether_shost));
  //
  printf("mac address: [%02X %02X %02X %02X %02X %02X]->"stEth->ether_shost[0], stEth->ether_shost[1],stEth->ether_shost[2],
  stEth->ether_shost[3],stEth->ether_shost[4],stEth->ether_shost[5]);


  printf("[%02X %02X %02X %02X %02X %02X]\n", stEth->ether_dhost[0],stEth->ether_dhost[1],stEth->ether_dhost[2],
  stEth->ether_dhost[3],stEth->ether_dhost[4],stEth->ether_dhost[5]);

  printf("packet type : ");
   
  switch(ntohs(stEth->ether_type))//big endian으로 바꾸는 함수를 스위치문 인자.
 {
    case ETHERTYPE_IP:
                          printf("IP\n");
                        //L2_IP(ucdata+14);
                          break;
    case ETHERTYPE_ARP:
                              printf("Address resolution\n");
                              break;
    case ETHERTYPE_REVARP:
                                  printf("Reverse ARP\n");
                                  break;
      
    default:
            printf("unknown: %04X\n", ntohs(stEth->ether_type));
            break;  


  }
//스위치문에서 해당패킷이 선택되어 지면, 해당 printf()문을 출력한다.  
  
  return (ntohs(stEth->ether_type));스위치문에서 선택된 ether타입을 반환한다.
}















L2ip.c 함수
각종 ip, tcp와 같은 패키지를 화면에 출력하는 함수. ip헤더부분을 나타낸다.


#include "ethernet.h"


int L2_IP(void *vp)
{
  struct ip * stIp=vp;
  unsigned short usChecksum;
  
  printf("ipversion              : IPv%d\n", stIp->ip_v);
  //0~4 4bit version

  printf("ipheader size          : %dbytes\n", (stIp->ip_hl)*4);
  //
0~4 4bit header length

  printf("type of service        : low delay  %s\n", (0==((stIp->ip_tos)&IPTOS_LOWDELAY))? "NO""yes");
  //8bit 
type of service

  printf("                         throughput %s\n", (0==((stIp->ip_tos)&IPTOS_THROUGHPUT))? "NO""yes");
  //total packet length

  printf("                         relability %s\n", (0==((stIp->ip_tos)&IPTOS_RELIABILITY))? "NO""yes");
  //
  printf("                         lowcost    %s\n", (0==((stIp->ip_tos)&IPTOS_LOWCOST))? "NO""yes");

  printf("total length           : %d\n", ntohs(stIp->ip_len));

  printf("identification         : %d\n", ntohs(stIp->ip_id));

  printf("flag                   : More  Fragment %s\n", (0==(ntohs(stIp->ip_off)&IP_MF))? "NO""yes");     

  printf("flag                   : Don't Fragment %s\n", (0==(ntohs(stIp->ip_off)&IP_DF))? "NO""yes");    
 

  printf("flagmentation off_set  : %d\n", ntohs(stIp->ip_off)&IP_OFFMASK);

  printf("time to live           : %d\n", stIp->ip_ttl);

  printf("프로토콜               : ");
                                     
  switch(stIp->ip_p)
  {
    case IPPROTO_IP:
      printf(" Dummy protocol for TCP\n");
      break;
      
    /*case IPTOS_THROUGHPUT:
      printf(" IPv6 Hop-by-Hop options\n");      
      break;*/

      
    case IPPROTO_ICMP :
      printf("Internet Control Message Protocol\n");
      break;
      
    case IPPROTO_IGMP:
      printf("Internet Group Management Protocol\n");
      break;
      
    case IPPROTO_IPIP:
      printf("IPIP tunnels (older KA9Q tunnels use 94)\n");
      break;
      
    case IPPROTO_TCP :
      printf("Transmission Control Protocol\n");      
      break;

    case IPPROTO_EGP  :
      printf("Exterior Gateway Protocol\n");
      break;
      
    case IPPROTO_PUP:
      printf("PUP protocol\n");
      break;
      
    case IPPROTO_UDP:
      printf("User Datagram Protocol\n");      
      break;
      
    case IPPROTO_IDP :
      printf("XNS IDP protocol\n");
      break;
      
    case IPPROTO_TP :
      printf("SO Transport Protocol Class 4\n");
      break;  
      
    case IPPROTO_IPV6:
      printf("IPv6 header\n");
      break;
      
    case IPPROTO_ROUTING:
      printf("IPv6 routing header\n");
      break;
      
    case IPPROTO_FRAGMENT:
      printf("IPv6 fragmentation header\n");
      break;
      
    default:
      break;

  }

  printf("%04x\n",stIp->ip_sum);
  stIp->ip_sum=0x0000;
  
  printf("check sum :%04x\n", smart_cksum(stIp,20));
  usChecksum=stIp->ip_sum;
  stIp->ip_sum=0x0000;
  printf("checksum check         : %s\n", (usChecksum==smart_cksum(stIp,(stIp->ip_hl)*4))?"ok":"fail");
  printf("IP Address             : [%s]->",inet_ntoa(stIp->ip_src));
  printf("[%s]\n", inet_ntoa(stIp->ip_dst));
  printf("IP Address             : [%s]->[%s]\n",inet_ntoa(stIp->ip_src),inet_ntoa(stIp->ip_dst)); 
  

  return stIp->ip_p;//stIp->ip_p 스위치문조건을 만족하는 해당 타입을 반환한다.
}





//체크 섬 함수.
unsigned short smart_cksum(void *vpData, unsigned int uiLen)
{
  unsigned long ulSum;
  for(ulSum =0;uiLen > 0;uiLen=uiLen-2)
  {
    ulSum = ulSum + *((unsigned short  *)vpData);
    vpData= (unsigned short *)vpData +1;
  }
  ulSum = (ulSum>>16) + (ulSum&0xffff);
  ulSum = ulSum + (ulSum>>16);
  return ~ulSum;
}
                              

ethernet.h 헤더파일

#ifndef _ETHERNET_H_
#define _ETHERNET_H_

#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <pcap/pcap.h>
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <netinet/in.h>

int L1_ethernet(void *vp);
int L2_IP(void *vp);
unsigned short smart_cksum(void *vpData, unsigned int uiLen);

#endif//_ETHERNET_H_ 


posted by 송시혁
2013. 7. 11. 16:18 네트워크/vmware 실습



getsockopt()함수 사용예제

1. 인자는 소켓번호

2. 두 번째 인자는 SOL_SOCKET

3. SO_SNDBUF는 이름그대로 버퍼를 전송한다는 의미.

4.자료형은 int, 전송할 버퍼를 말한다.

5. 전송할 버퍼의 크기를 정한다. 자료형이 int라서 4byte가 되겠다.




unsigned uiTemp에 63*1024 집어넣어 버퍼의 크기를 변경하여 출력해봄.

최대 크기는 64이다. 64이상 되는 크기는 똑같은 바이트크기가 나온다. 최대 한계치가 존재하는 것이다. 여기서는 64가 제일 크다고 

생각하면 되겠다. 그래서 63까지 변경이 가능한다. 아래는 실행결과.






아래 소스는 gethostbyname()함수이다.

메인함수의 인자로 실행방법을 정한다. 그러니까 실행시 ./파일명 인터넷.com등을 쳐야 해당 인터넷의 ip주소가 

나오게끔 설정을 해놓았다.




구조체 변수 2개를 설정한다. 이것은 정해쳐 있는 구조체이므로 만들어서 사용하는 것이 아니다. 이미 정해져 있다. 

gethostbynaem()함수의 인자로 main()함수의 인자를 넣는다. 여기서 argv[1]은 찾고자 하는 해당 인터넷이 되겠다.

이것을 반환한다. 구조체형 포인터를 반환하므로 myent또한 구조체형으로 선언되었다.


while문에서 괄호안에 조건을 보면 *myent->h_addr_list가 NULL이 아니면, 즉 밑에 소스를 해석해보면 알겠지만,

 *myent->h_addr_lis가 가르키는 값, 즉 여기서는 해당 인터넷의 도메인 주소가 0이 아닐 때까지 실행한다.


add가 long int 형이므로 캐스팅를 한다.

그리고 myen.s_addr= *add; 구조체 멤버 어드레스에 add가 가르키고 있는 값을 넣는다.

이것을 아래 printf문에서 네트워크를 아스키로 바꿔주는 함수로 문자열을 출력한다.


그런다음, myent->h_addr_list++ 포인터형이라 *을 빼면 주소가 되므로 주소를 한 칸 이동시켜 그 다음에 있는 주소(도메인)을 가르킨다.


그래서 아래 그림에 도메인 주소가 출력된다. 





posted by 송시혁
2013. 7. 11. 16:14 네트워크/vmware 실습

브로드 캐스트 

ip는 udp에서만 사용가능.


브로드캐스트 send부분

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

void DieWithError(char * errorMessage);

int main(int argc, char *argv[])
{
  int sock;
  struct sockaddr_in broadcastAddr;
  char * broadcastIP;
  unsigned short broadcastPort;
  char * sendString;
  int broadcastPermission;
  unsigned int sendStringLen;
  if(argc <4)//main인자가 4보다 작을 경우 에러처리, 즉 실행시 ip주소를 같이 쳐야 하므로 에러처리를 4보다 작으면
 { //으로 지정
    fprintf(stderr, "Usage: %s <IP Address><Port><Send Sting>\n", argv[0]);
    return 1;
  }
  broadcastIP= argv[1]; //IP는 "192.xxx.....문자열이므로 그냥 넣어도 된다. 실행이름을 적을시 2번째로 ip를 적는다.
  broadcastPort= atoi(argv[2]);//포트는 번호이기 때문에 아스키문자를 정수형으로 변환한다.
  sendString=argv[3]; //직접 브로드캐스트 Recv로 보내는 데이터.

  sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);   //IP에서 udp만 브로드캐스트 할 수 있다.
  setsockopt(sock, SOL_SOCKET, SO_BROADCAST,(void *)&broadcastPermission  ,sizeof(broadcastPermission));
//이 함수에서 

  memset(&broadcastAddr, 0sizeof(broadcastAddr));
  broadcastAddr.sin_family= AF_INET;
  broadcastAddr.sin_addr.s_addr = inet_addr(broadcastIP);
  broadcastAddr.sin_port = htons(broadcastPort);
//여기까지는 구조체 설정부분. 알고 있으므로 생략

  sendStringLen= strlen(sendString);//변수에 전송 데이터 문자열 크기만큼 대입. , 즉 전송하는 데이터 크기.

  for(;;)
  {
    sendto(sock, sendString, sendStringLen, 0,
    (struct sockaddr *)&broadcastAddr,sizeof(broadcastAddr));//소켓에 데이터를 넣는 부분. 브로드캐스트 주소에 그 크기만큼의 주소를
//전송할 문자열 데이터를 소켓에 집어넣어 보내는 함수이다. 
    sleep(3);//문자를 전송할 때 까지 대기하다가 보내지면, 자동 종료.
  }
}



브로드캐스트 recv부분.




#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAXRECVSTRING 255

void DieWtihError(char * errorMessage);
int main(int argc, char *argv[])
{
  int sock;
  struct sockaddr_in broadcastAddr;
  unsigned int broadcastPort;
  char recvString[MAXRECVSTRING+1];
  int recvStringLen;
  if(argc != 2)// 실행시 ./파일명 포트번호 이런형식으로 출력하지 않는 경우 다음과 같은 메시지 출력.
  {
    fprintf(stderr, "Usage: %s <Broadcast Port>\n", argv[0]);
    return 1;
  }  
  broadcastPort = atoi(argv[1]);// ip번호 
  sock= socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  memset(&broadcastAddr, 0sizeof(broadcastAddr));
  broadcastAddr.sin_family = AF_INET;
  broadcastAddr.sin_addr.s_addr=htonl(INADDR_ANY);
  broadcastAddr.sin_port=htons(broadcastPort);

  bind(sock, (struct sockaddr *) &broadcastAddr, sizeof(broadcastAddr));
 //broadcastAddr 주소에 크기만큼 소켓에 넣는다.

  recvStringLen = recvfrom(sock, recvString ,MAXRECVSTRING, 0, NULL, 0);
//소켓에서 메시지를 받느다. 소켓에 데이터를 받는 함수 recvfrom(), 메시지의 길이를 반환하므로
//변수 int형 
recvStringLen에 값을 넣는다.

  recvString[recvStringLen] = '\0';// 끝에 문자열 널을 넣기 위한 부분.
                                    //넣지 안으면 끝에 이상한 문자가 찍힌다. 왜냐하면 '널'이 있어야 문자열로 인식한다.
  printf("Received: %s\n", recvString);//출력
  close(sock);
  return 0;
}     


실행 결과


posted by 송시혁
2013. 7. 10. 17:36 네트워크/vmware 실습



아래 그림과 같이 구조체를 만든다. 나중에 이 구조체를 함수의 인자로 넘긴다.

그리고 두 개의 전역변수인 uiUser와 stpLink[MAXUSER]를 유심히 봐야한다.


위의 구조체가 vp로 넘긴다.






아래는 함수의 전체 소스.



아래 그림의 전역변수stTempinfo.uiUser= uiUser;에서 접속자의 번호를 집어넣는다.

그리고 쓰레드를 생성한다.  마지막 인자의 stTempinfo를 ClientRecv함수의 인자로 넘긴다.
stTempinfo의 주소가 vp인자로 넘겨진다. 즉, 구조체가 넘겨지는 것이다. 



함수에서 구조체형 Tinfo stMyInfo를 선언한 뒤, 바로 vp를 대입한다.

물론, 캐스팅을 해줘야하며, vp는 stTempinfo의 주소이기 때문에 포인터 *을 앞에 붙여서 대입한다.

전역변수 구조체 Tinfo형 포인터 배열인 stpLink[]에 인덱스와 대입되는 값을 주의깊게 본다.

이 부분에서 stMyInfo는 클라이언트로부터 송신된 데이터, uiUser, iSock ,tID, (접속자, 번호, 쓰레드 번호)

등 첫 번째 원소인 stMyInfo주소(포인터 배열이기 때문에)에 넣는다. 

아래 0을 집어넣는 것은 main()함수에서 


이 부분때문이다. 여기서 while문을 쓴 이유는 서버에서 ClientRecv()함수가 데이터를 받아 값을 집어넣는 시간을 

벌기 위해서이다. 지연을 시키지 않으면, 현재에 가지고 있는 값을 처리하기도 전에 다음 데이터 값을 덮어씌여버리는

현상이 발생할 수 있기 때문에 while문으로 지연시킨다. ((Tinfo*)vp)->iSock=0;이 실행되면 while문을 빠져나가 아래 코드가 비로소 실행이 된다.




두 번째 빨간색 네모 보류....

배열 인덱스에 해당하는 값을 집어넣고 클라이언트가 로그아웃했을 때의 접속자 번호를 앞으로 당겨 변경하는 코드인데

자세히 모르므로 보류, 나중에 정리 하겠음.











posted by 송시혁
2013. 7. 9. 14:46 네트워크/vmware 실습


다음예제는 TCPserver소스


#include "smart.h"
#include <pthread.h>

#define MAXPENDING   5
#define MAXUSER    10
void *ClientRecv(void *);

////// Critical Section  Start////
unsigned int    uiUser;
pthread_t       tID[MAXUSER];
///////// 크리티컬 섹션 End//////
pthread_mutex_t    MLock;

int main(int iArg, char *cpArg[])
{
  int servSock; 
  int clntSock[MAXUSER];
  int tempSock;
  struct sockaddr_in echoServAddr;
  struct sockaddr_in echoClntAddr;
  unsigned short echoServPort;
  unsigned int clntLen;
  int iRet;
  int iCnt;
  int iCnt2;
  unsigned char ucBuff[500];
  
  if(iArg)
  {
    echoServPort=9998;
  }    
  else if(2==iArg)
  {
    echoServPort=atoi(cpArg[1]);
  }
  servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if(0 > servSock)
  {
    printf("socket() failed");

    return 0;
  }




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

  iRet = bind(servSock, (struct sockaddr *)&echoServAddr, sizeof(echoServAddr));
  if(0 > iRet)
  {
    close(servSock);
    printf("bind() failed");
  
    return 0;
  }

  iRet = listen(servSock, MAXPENDING);
  if(0 > iRet)
  {
    close(servSock);
    printf("listen() failed");

    return 0;
  }

  clntLen = sizeof(echoClntAddr);

  uiUser = 0;
  while(1)
  {
    tempSock = accept(servSock, (struct sockaddr *)&echoClntAddr, &clntLen);
    if(0 > tempSock)
    {
      printf("accept() failed");
      continue;  
    }  
    printf("Handling client ip : %s\n", inet_ntoa(echoClntAddr.sin_addr));
    printf("Handling client port : %d\n", ntohs(echoClntAddr.sin_port));
    printf("Handling client socket number : %d\n", tempSock);
    if(MAXUSER <= uiUser)
    {
      close(tempSock);
      continue;
    }
    
    pthread_mutex_lock(&MLock);//mutex 동기화 매카니즘 함수중의 하나.
    pthread_create(&tID[uiUser],0, ClientRecv, &tempSock); //uiUser는 접속자수, 세번째 인자는 ClientRecv함수를 호출.
    ++uiUser;
    pthread_mutex_unlock(&MLock);

    
    while(0!=tempSock);// 여기서 지연시키지 않으면, 쓰레드를 생성해서 쓰레드가 가지고 있는 데이터가 잘못될 수 있기 때문.
                           //
    printf("현재 접속자 수 : %d\n", uiUser);//
  }
  
  close(servSock);  
  
  return 0;
}

void *ClientRecv(void *vp)
{
  int iSock = *((int *)vp);// ClientRecv가 클라이언트의 데이터를 인자로 받고 변수 iSock에 집어넣는다.
  unsigned char ucBuff[500];
  int iRet;
  
  *((int*)vp)= 0;//
  
  while(1)
  {
    iRet = read(iSock, ucBuff, 500);//iSock에 있는 데이터를 읽어들인다. (클라이언트 정보 읽는다.)
    if(1>iRet)
    {
      break;
    }
    
    ucBuff[iRet-1]=0;//엔터제거
    printf("[%dsock]:[%s]\n", iSock, ucBuff);//번호와 문자열(수신된 데이터)
    if('$'==ucBuff[0])
    {
      break;
    }
  }
  --uiUser;//유저수를 감소시킨다.
  close(iSock);
  return 0;
  
}










세밀하게 수정 된 부분.


#include "smart.h"
#include <pthread.h>
#define MAXPENDING   5
#define MAXUSER    10

typedef struct _Tinfo
{
  unsigned int   uiUser;
  int        iSock;
}Tinfo;

void *ClientRecv(void *);

////// Critical Section  Start////
unsigned int    uiUser;
pthread_t       tID[MAXUSER];
///////// 크리티컬 섹션 End//////
pthread_mutex_t    MLock;

int main(int iArg, char *cpArg[])
{
  int servSock; 
  Tinfo stTempinfo;
  struct sockaddr_in echoServAddr;
  struct sockaddr_in echoClntAddr;
  unsigned short echoServPort;
  unsigned int clntLen;
  int iRet;
  int iCnt;
  int iCnt2;
  unsigned char ucBuff[500];
  
  if(iArg)
  {
    echoServPort=9998;
  }    
  else if(2==iArg)
  {
    echoServPort=atoi(cpArg[1]);
  }
  servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if(0 > servSock)
  {
    printf("socket() failed");

    return 0;
  }

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

  iRet = bind(servSock, (struct sockaddr *)&echoServAddr, sizeof(echoServAddr));
  if(0 > iRet)
  {
    close(servSock);
    printf("bind() failed");
  
    return 0;
  }

  iRet = listen(servSock, MAXPENDING);
  if(0 > iRet)
  {
    close(servSock);
    printf("listen() failed");

    return 0;
  }

  clntLen = sizeof(echoClntAddr);

  uiUser = 0;
  pthread_mutex_init(&MLock, NULL);//NULL로 초기화하는 함수.
  while(1)
  {
    stTempinfo.iSock = accept(servSock, (struct sockaddr *)&echoClntAddr, &clntLen);
    if(0 > stTempinfo.iSock)
    {
      printf("accept() failed");
      continue;  
    }  
    printf("Handling client ip : %s\n", inet_ntoa(echoClntAddr.sin_addr));
    printf("Handling client port : %d\n", ntohs(echoClntAddr.sin_port));
    printf("Handling client socket number : %d\n", stTempinfo.iSock);
    if(MAXUSER <= uiUser)
    {
      close(stTempinfo.iSock);
      continue;
    }
    
    pthread_mutex_lock(&MLock);
    stTempinfo.uiUser=uiUser;
    pthread_create(&tID[uiUser],0, ClientRecv, &stTempinfo);//
    ++uiUser;
    pthread_mutex_unlock(&MLock);//

    while(0!=stTempinfo.iSock);// 
    printf("현재 접속자 수 : %d\n", uiUser);
  }
  
  close(servSock);  
  
  return 0;
}

void *ClientRecv(void *vp)
{
  unsigned char ucBuff[500];
  int iRet;
  int iSock = ((Tinfo *)vp)->iSock;
  unsigned int uiMyUser=((Tinfo *)vp)->uiUser;
  
  ((Tinfo*)vp)->iSock= 0;
  
  while(1)
  {
    iRet = read(iSock, ucBuff, 500);
    if(1>iRet)
    {
      break;
    }
    
    ucBuff[iRet-1]=0;
    printf("[%dsock]:[%s]\n", iSock, ucBuff);
    if('$'==ucBuff[0])
    {
      break;
    }
  }
  pthread_mutex_lock(&MLock);
  --uiUser;
  tID[uiMyUser]=tID[uiUser];
  pthread_mutex_lock(&MLock);
  close(iSock);
  return 0;
  
}



posted by 송시혁
2013. 7. 8. 16:41 네트워크/vmware 실습



아래 그림은 makefile이다.  실행하고자 하는 파일 이름을 TRG에 넣고 아래 그림과 같이 만들면,
힘겹게 gcc -o main main.c -lpthread라고 칠 필요가 없다. 해석은 알고 있으므로 생략하겠다.





posted by 송시혁
2013. 7. 8. 16:15 네트워크/vmware 실습

위의 define문을 보면FILE_SOCKET이 "../SMART_SCOKET"정의 되어 있다.


unlink()함수에서 인자로 define한 값을 받는다. UNLINK는 define한 이름의 파일을 지우는 역할인데 여기서 호출한 이유는 혹시나 같은 이름의 

파일이 있을지 모르니 호출하였다.


소켓함수의 AF_UNIX가 인자로 사용되었다. 이부분 보류 잘모름. OTL.....


struct sockaddr_un부분을 본다.



#define __SOCKADDR_COMMON(sa_prefix) sa_family_t sa_prefix##family

sa_prefix <= sun_

sa_family_t sa_prefix sun_family

 #define __SOCKADDR_COMMON_SIZE  (sizeof (unsigned short int))

이 define에서 __SOCKADDR_COMMON_SIZE 이 sizeof로 unsigned short int크기로 define.


struct sockaddr_un
{
  
  _SOCKADDR_COMMON (sun_));=>여기 이부분은  sa_family_t sun_family;이 된다.
  char sun_path[108];
  
};
그래서 결국 아래와 같은 구조체가 된다.
struct sockaddr_un
{
  sa_family_t sun_family;
  char sun_path[108];//길이를 
  
};
typedef unsigned short int sa_family_t;

21번라인에서 stSAddr.sun_family = AF_UIX;가 된다.

strcpy(stSAddr, FILE_SOCKET)-> FILE_SOCKET을 stSAddr로 복사한다.

iStructSize=sizeof(struct sockAddr_un)=iStructSize에 구조체 크기를 설정한다.


while문 내부

변수 선언 가능한다. 중괄호 내에서만 실행가능한 변수이다.


다음 명령을 친다. 그 이유는 AF_UNIX 실행파일을 VMWARE에서 실행할 수 없기 때문에

리눅스 공유폴더 밖에서 실행해야 한다. 실행파일을 그래서 리눅스공유폴더보다 상위폴더에로 가져와서 실행해야 한다.



home디렉토리에서 SMART.SOCKET=이 생성되어 있는 것이 보인다.


클라이언트





여기 소스에서 잘못된부분이 있는데 close(iCSock);를 return 0;전에 삽입하여야 한다. 지금 이소스대로 하면, 메시지를 한 번 전송하고

클라이언트가 꺼져 버린다. 그렇기 때문에 반드시 return 전에 사용하여야 한다.












posted by 송시혁
2013. 7. 5. 12:06 네트워크/vmware 실습


posted by 송시혁
prev 1 2 3 next