'socket'에 해당되는 글 5건

  1. 2008.02.28 gethostbyname 의 세그멘테이션 오류 2
  2. 2006.07.18 소켓shutdown..DomainName<->IP
  3. 2006.07.18 TCP/IP 추가 and UDP /IP
  4. 2006.07.15 소켓 프로그래밍 part 2~4 TCP/IP 4
  5. 2006.07.06 열혈강의 TCP/Ip Socket Programming --Part 1 1

gethostbyname 의 세그멘테이션 오류

이것도 제목이 풰이크가 되네요 적어 놓고 보니 -_-;............

몇달전에 만든 소켓라이브러리

(라고 해봤자 전 프로그램에 썻던 소스코드 모음.. 지금은 bind,connect등 함수 순서조차도 기억이 안남..)

를 써서 GET 으로 인터넷 웹페이지를 긁어오는 짓을하고 있었는데요...

자꾸 gethostbyname 함수 에서 세그먼트에러가 나는 바람에 왜그런가 했는데..

(gdb가 여기서 난다고 했다! 난 이녀석을 철석같이 믿었것만! )

그래서 여기만 뚫어져라 쳐다보고 있었는데 라이브러리에서 오류 먹은걸 나보고 어쩔???

하다가 중간에 에러메세지를 자세히!(전 까진 대충,..) 보니까 malloc어쩌구~ 라고 나오길래..

(gethostbuname 함수내부 에서) 이걸 동기로 해서...

분명히 그럼 네 소스어딘가오류가 있겠지하고서 뒤저보니까..................

원인을 찾았다... !!!

"서버에 보내는 정보가 잘못되서" 였다 "Cokie:" 이렇게 한번만 해야할걸 "Cookie: Cookie: " ... 이런식으로 보내서..

그럼 오류가 날려면 send함수에서 나야지 왜 여기서 나는지 도저히 이해할수가 없다....

gethostbyname은 그냥 DNS주소를 IP주소로 변환해주는 기능밖에 하지 않는데...

가 아니라..................;

이건또 뭥미?? 중간에 malloc size를 잘못 정해주어서 였네요..

할당할 메모리 크기를 리턴해주는 함수가 있었는데.. 거기서 크기를 잘못 리턴해 주는 바람에

(필요한 크기보다 더 작게 할당해서 쓰는범위가 할당한범위를 넘겨버렸어요.......; )

전혀~ 상관 없는 gethostbyname 함수가 세그먼트 오류를 먹으면서 뻣어버린것.........

제대로 free,malloc을 못하면 세그먼트 오류가 난다고 하는데.. 실제로 이런거 겪어보긴 처음이라...

(free도 아니고 malloc이...free는 많이 격어 봐서 적응이 되지만..)

소켓을 건들땐 valgrind가 느려서 안썻더니만.. 이런 문제가 발생하네요...

(에뮬레이팅을 하다보니 소켓같은건 좀 느린가 보다......)

소켓같은 데서도 valgrind를 사용할수 있었으면 좋겠네여........

 뭐 제가 방법을 모르는거 겠지만요.... 누구 아는 분 댓글점...

'Programming > Networking' 카테고리의 다른 글

소켓shutdown..DomainName<->IP  (0) 2006.07.18
TCP/IP 추가 and UDP /IP  (0) 2006.07.18
소켓 프로그래밍 part 2~4 TCP/IP  (4) 2006.07.15
열혈강의 TCP/Ip Socket Programming --Part 1  (1) 2006.07.06

소켓shutdown..DomainName<->IP

여태까지 우리는 소켓을 보낼때 close함수로 소켓을 닫았습니다

하지만 이럴때에 만약 한쪽에서 보낸 데이터를 보냈는데 받는측에서는 벌써 close함수가 호출되

어서 Pipe 가 (올바른 표현인가는 모르겠습니다만)  닫혀버린다면... 보낸 그 데이터는 유령 데

이터가 되어 버리겠죠..

음 자세히 설명하자면...


A------------------------------------>B
A<------------------------------------B
상황에서

A--------------data-------X------>B(close run)
A<------------------------X----------B
이런 상태가 되면 난감하니까..(close 함수로 끝내면 다 닫혀 버림..)


A----X--------------data--------->B
A<---------data--------------------B
바로 전달하고 막아버림

아 몰라... 일단 반씩 소켓을 닫는 함수를 소개하자면..

int shutdown(int sockfd,int how);
이 함수는 무쟈게~ 간단합니다...
자꾸 파이프가 생각나네요 흠..
뭐 암튼... 인자는

sockfd:............소켓 fd
how:012가 있습니다.. 각 순서는 stdin,stdout을 생각해보시면 잘 알수 있으실겝니다..

라고 해도 설명을 해야겠죠 흠..
0:입력스트림 종료 1:출력스트립 종료 2:둘다 종료
0:SHUT_RD 1:SHUT_WR 2:SHUT_RDWR 이렇게 쓰기도 합니다..
이것들은 open함수에서써먹었던 놈들이 생각나네요.. 끝부분이 비슷하죠......;;;;;;;;;;;;

도메인 이름을 -> IP 로 IP를 ->도메인 네임으로!!
새로운 구조체 등장!

#include<netdb.h>

struct hostent{
   char h_name;
   char **h_aliases;
   char h_length;
   char **h_addr_list;
}

h_name:딱 보면 나오지않는가! 바로 공식 호스트 네임 ex>www.naver.com
h_aliases:더블포인터..이라하면 여러개를 가르키는.. 그리고 이름을 보자 alias...
떠오르는게 없을려나! 바로..비슷한 이름을 치면 공식 호스트 네임의 서버로 들어가는것
설명이 더 힘들다 간단한 ex>www.naver.co.kr,  naver.com
h_addrtype: ipv4(걍 여태까진 ip4라고 했죠? 귀찮아서 축약)ip6인지 알아낼수 있습니다
h_length:주소의 길이,위의 값에 따라 달라진다 버전4==4 버전6==16
h_addr_list:넣은 도메인 이름의 IP 큰회사일경우 IP가 여러개 찍힐수 있다(서버 갯수가 많으므로)그것때문에 2차원 포인터.

이 구조체로 써먹을수 있는 함수들은..

1.도메인이름으로  IP주소와 그에 따른 정보 알아보기
struct hostent* gethostbyname(const char * name);
성공시 hostent구조체 반환,즉 이 함수가 성공하면 걍 구조체안의 변수들을 출력하기만
하면 호스트의 정보를 볼수 있다
인자는 볼것도 없다.. 그냥 따옴포 치고 넣어주던가 아님 argv로 받아서 넘겨주면 끝

2.아까꺼랑 반대로 .. IP로 도메인 이름 알아보기
struct hostent* gethostbyaddr(const char *addr,int len,int type);
addr:(char *)&addr.sin_addr 을 넣어주면 된다..
(뭐 당연히 addr은 구조체를 뭘 했냐에 따라서 다르다)
len:ipv4==4 ipv6==16을 넣어준다
type:말 그대로 타입..AF_INET,AFINET6 를 선택해서 집어넣는다(각 ipv4 ipv6)

**혹시 해서 적는데.. 포인터로 받으니까.. 에러시 리턴값은 NULL이다

TCP/IP 추가 and UDP /IP

Iterative 서버의 구현

while(1)
{
   client_fd=accept(&ser_sock,(struct sockaddr *)&client_addr,&client_addr_size);
         //에러 처리는 알아서 하자 귀차너//
   write(client_fd,SendMessage,sizeof(SendMessage)):
   close(client_fd);
} //아라.. 다시 보니깐 read 안썻네..

내 개인적인 생각이지만 다른거라면 while을 돌려서 쉬지 않게 메세지를 받게 하는 기능 정도만
추가된거 같다

음 근데 왜 accept함수를 while 문 안에 넣느냐 하면.. 아니 설명할 필요도 없나..
뭐 한번더 기억을 상기시켜 보자면은.. accept함수가 메세지를 입력 받는 함수이다(뭐라하는건지 쿨럭;)
라서 이다 ,;;

그림으로(?) 그려(?) 보았다 ....

socket() -> bind() ->listen() -> accept() -> file in/out -> close(client) ->close(server) ->END
                                                             |__________________________|
                                                                             while(1)

(책에서는 서버를 닫아주지 않았다... 끝날때 알아서 종료 되니깐 귀찮아서 안한거 같다....)

다른게 있다면 저~기 While 문을 썻다는거 뿐!


Plus! Packet

서버랑 클라이언트랑 메세지를 전달할때(아래서 부턴 패킷으로 부름) 크기가 정해져서 수신/전송이
되는게 아니다(라고 한다)
그래서 클라이언트일경우 쓴만큼 읽어 들여야 한다..

뭐어 대충 구조는 다음과 같다

1.write call해서 일단 쓴다..write함수의 리턴값을 저장하고서(이값이 read시 Max값이 되겠죠?)
wr=write(~);

2.반복문을 돌린다(while이든 for이든.. ) ex>for(i=0~

3. 반복문 안에 read함수를 넣고 리턴값을 받는다(이 리턴값은 read한 크기입니다) 에러처리를 하고 싶으면 한다 ex> rd=read(~);

4.i값이랑 read함수에서 받은 리턴값이랑 합산애서 i에 대입 ...i+=rd

5 증가값은 적지마시고 최대 Max값이 i 값보다 작을때까지 반복

이거 했갈릴테니깐 코드로 작성하믄

wr=write(sockfd,buf,strlen(buf)):

for(i=0;i<wr;)
{
   rd=read(sockid,&buf[i],wr-i);//에러 작성문은 알아서 만듭시당..
   i+=rd;
}
-------------------아놔... 제가 만들어 놓고서 뭐라고 적어논건지 모르겠어요----------------------

UDP? User Datagram Protocol 이랍니다.

데이터의 경계가 있기때문에(빼먹었는데 TCP에는 없습니다)클라이언트에서 질의를 3번하면
서버에서 응답을 3번해야한다는겁니다(그런거 같았;;)

그리고 TCP와는 달리 2개가 서로 연결되어서 통신하는게 아니기 때문에.. 간단하고 속도가 빠릅니다.

다음은 UDP 프로그램의 기본적 구조

server:구조체선언->구조체의 값 집어넣기->bind->입/출력.반복->소켓 닫음
(listen,accept함수가 없습니다)

client:구조체 선언->구조체에 값 집어넣기->파일 입출력(반복)->소켓 닫기
(connect 함수를 안써도 됩니다(때에 따라서))

동영상 스트리밍 서비스 같은데 많이 사용한다고 하더군요..빠른속도로 보내야 하니까요.. 대신 데이터

손실를이 높으니까 파일전송같은덴 알맞지가 않겠네요

뭐 암튼 TCP와는 다르게 파이프처럼 서로 연결된게 아니고 보내고 끝이라는 겁니다.

그렇기 때문에 보내고 받는함수를 read,write하지 말고 특수한 함수를 사용해야 한다네요

int sendto
(int sock,const void *meg,int len,unsigned flags,const struct sockaddr * addr,int addrlen);
sock:socket함수의 리턴값
meg:전송할 데이터를 저장하는 버퍼를 가르키는 포인터(이 포인터가 가르키는 곳으로 부터 데이터전송시작)
len,meg의 포인터가 가진 기점으로부터 몇바이트를 보낼것인가?(sizeof~)
flags:옵션,일반적으로 0을 넣어줌 자세한건 man페이지 참조
addr:앞에서 절라 써먹던 그 구조체
addrlen:앞에서 절라 써먹던 그 구조체의 크기

int recvform(int sock,int *buf,int len,unsigned flags,struct sockaddr * addr,int *addrlen);
sock:이건 정말 말하기 지겹다
buf:받은 데이터를 저장할곳을 가르키는 포인터
len:수신할수 있는 최대 바이트 어지간하면 buf값을 넘지 않도록 주의 한다
flags:전과 상등
addr:주소 정보 구조체 변수의 포인터를 인자로 넘김,다 완료되면 데이터를 전송한 호스트의 정보가 이
구조체에 저장되게 된다
addrlen:addr포인터의 크기를 가진 변수의 주소를 넘긴다

포트정보는 sendto 쓸때 같이 보내진다고 합니다

Plus! Connect 함수 사용
이 함수를 사용하면 일단 커널과 소켓간에 연결을 유지하면서 통신할수 있습니다.
(걍 TCP/IP 쓸때처럼 Connect함수를 while돌리기 전에 써주면 끝입니다)
그래서 속도향상을 꽤할수 있고.. 미리 정보를 전달해 주기때문에.. sendto,recvform 함수를 쓰지
않고서 read,write같은 함수를 입출력을 해도 된다고 하네요..

소켓 프로그래밍 part 2~4 TCP/IP

TCP/IP 소켓 프로그램의 기본적 예제

                     대략적 구조
Server ------------------------------Pipe-------------------------------------Client

socket 함수                                                                                       socket 함수
      |                                                                                                     |
bind 함수                                                                                          Connect 함수
      |                                                                                                     |
listen 함수                                                                                               |
      |                                                                                                     |
accept 함수                                                                                               |
      |                                                                                                     |
read,write                                                                                          read,write
send,recv함수                                                                                     send,recv함수
      |                                                                                                      | 
  소켓닫기                                                                                            소켓닫기


세부사항

<SERVER>

0> 해더파일을 삽입한다
#include<stdio.h> printf();
#include<stdlib.h> exit();
#include<string.h> memset();
#include<arpa/inet.h> socket();.......
#include<sys/types.h>      ''
#include<sys/socket.h>    ''


1>sockaddr_in 구조체를 선언한다...
ex>struct sockaddr_in server; (타입케스팅 할땐 struct sockaddr *)


2>struct 구조체 안의 변수에 값들을 채워준다,

bind등의 함수가 이 구조체의 값을 사용한다

sockaddr_in 구조체의 내부 변수들은 다음과 같이 설정해 준다

ex>
memset(&server,0,sizeof(server)); //구조체 할당하기전에 먼저 초기화
server.sin_family=AF_INET;    //IP의 성격 설정 대부분 ip4를 사용하므로 이렇게 설정
server.sin_port=htons(atoi(argv[1])); //host->Network (type short)
server.sin_addr.s_addr=htonl(INADDR_ANY); //host -> Network (type long) 일단 그냥 외우자

INADDR_ANY는 현재 자신의 IP주소를 말한다 지금 설명하는 프로그램은 서버이므로 자기 자신의
IP를 저장하고 있어야 한다

 
3>소켓을 만들어 준다

(listen함수에서 만들어진 큐을 제어하는 소켓이다 클라이언트와 연결되 작업하는그런 소켓이
아님을 명심하자)

       if((sockid=socket(AF_INET,SOCK_STREAM,0))==-1){
               perror("Socket Created ERROR");
               exit(1);
               }

아래는  man 페이지 수정/추가>

소켓은 지시된 통신 semantics를 지정하는 type 을 갖는다.  현재 정의된 타입은 다음과 같다:

      SOCK_DGRAM  <UDP>
             데이타그램 지원

      SOCK_STREAM    레코드 경계를 보호하진 않는다.  스트림 소켓은 모든 데이타가 그것으로  송수신 되기전에 접속 상태이어야한다.  <TCP/IP>
 
에러가 생겼을때 socket함수는 -1을 리턴 한다는걸 알수있다..
아래껏도 대부분 그렇다

4>bind 함수를 만들어 준다,각 주소로 연결하는 함수


       if(bind(sockid,(struct sockaddr *)&server,sizeof(server))==-1){
               perror("Socket Bind ERROR");
               exit(1);
       }

bind(소켓 파일디스크립터,sockaddr_in 구조체 주소
(꼭 타입 케스팅 할것!), 구조체의 크기);

여기서 소켓 파일 디스크립터란(또는 id?) 그리고 타입케스팅 할때 _in 빼자

5>대기열 생성

       if(listen(sockid,5)==-1){
               perror("Listen ERROR");
               exit(1);
       }

간단한 함수...
listen(소켓 id,대기 큐 갯수);
대기열을 왜 만드냐하면... 클라이언트가 한번에 여러개 접속할수 있으니까...
막 일려올때 순서를 정해서 일을 처리하기 위해서*/

6>연결 허용 accept함수

aceept함수는 크기를 줄때 주소로 주어야 한다
또 이함수는 새로운 소켓 id을 반환한다..

추가> 아까 만든 소켓을 대기큐를 제어하는데 쓰이는 소켓
이번에 만들어진 소켓이 정말 데이터를 처리한다*/

       faccept=sizeof(client);//주소 때문에 이렇게 함

               if((sockid2=accept(sockid,(struct sockaddr *)&client,&faccept))==-1){
                       perror("Aceept ERROR");
                       exit(1);
               }

accept함수의 리턴값이 바로 accept함수가 만들어준 새로운 소켓의 파일 디스크립터이다

7>나머지는 파일 입출력과 같다..

이 파일 디스크립터로 네트워크의 호스트에 연결된것이다 이 리턴된 파일 디스크립터 로 일반 표준 입출력
처럼 사용하면 된다(파이프를 연상하면 그나마 비슷할까)*/

       while(1)
       {
               read(sockid2,buf,100);
               printf("%s",buf);
               write(sockid2,buf,100);
       }

8>소켓을 닫는것을 일반 파일과 같게 적용되기도 한다
               close(sockid2);

절대 강조! (나에게 쓰는 메세지)
리턴값 처리해줘야 하는 함수는 socket(),accept() 함수 밖에 없다!!
(이상한거 리턴받아 쓰지 말자!!!!!!!!)

<Client>
(여기서 숫자는 서버의 단계 숫자)

일단 0~3까지의 순서는 SERVER와 같다
4~6의 과정은 쓰지 않는다
그러므로 생략 중간에 Connect함수쓰는거 빼면
7~8번째도 같다

이번엔 귀찮으니깐 Connect함수만 쓰도록 한다

if(connect(sockid,(struct sockaddr *)&server,sizeof(server))==-1){
    perror("Connect ERROR");
      exit(1);
}
뭐.. 설명이 필어 없을듯 하다 인자는 Bind함수랑 비슷하다(같은건가?)
서버와 연결을 할때 쓰는 함수다

7>
단 read,write쓸때
read 하면 클라이언트에서 받을거고
write하면 클라이언트에서 메세지를 보낸다
라는 약간의 차이가 있다
파일 디스크립터(클라이언트 에게 보넬 입출력 fd) 는 소켓을 생성한 파일 디스크립터에다가
read,write하면 된다

8> 번에 대해서는 뭐 당연하다고 생각하는데로 생각하면 된다

서버와 연결을 할때 쓰는 함수다  자세한건 Manpage~

열혈강의 TCP/Ip Socket Programming --Part 1

간단하게 정의
(클라이언트, 서버는 네트워크에 연결되어 있다고 가정)

클라이언트:정보를 보내는 프로그램(요청)
서버:정보를 받는 프로그램(수락)
*서버와 클라이언트는 소켓으로 연결을 한다

서버 프로그래밍의 예시

--전화                                               소켓                                           관련 함수
전화 사기                                    소켓 생성하기                                      (socket 함수)
전화 번호 얻기                            아이피 주소 얻어오기                                  (bind 함수)
전화 케이블에 연결하기                    신호 요청 대기                                      (listen 함수)     
전화 걸기                                       연결수락                                           (accept 함수)        

클라이언트 프로그래밍의 예시

--전화                                               소켓                                           관련 함수
전화 사기                                    소켓 생성하기                                     (socket 함수)
연결 요청                                    소켓 연결하기                                      (connect함수)
         
TCP  트랜스미션 컨트롤 프로토콜 :말그대로 "제어"한다 IP라는거 자체가 데이터를 전달하는게 정확성이
없다 쉽게 말해서 보내주긴 보내주는데 제 주소에 보내지던 말던은 상관을 안한다는 얘기..
그리하여 그런 상황을 미연에 방지하기 위해서 데이터를 송/수신 할때마다 제대로 도착했는지를 확인하는
프로토콜 이라고 말하면 대충 되려나...

UDP 유저데이터그램 프로토콜: 이녀석은 확인 같은거 안하고 걍 보내고 끝. 그래서 속도가 빠르다고 한다나

포트:각각의 프로세스가 이 포트와 연결되 있고(물론 네트워크와 관련된 프로세스들)여기서 각 네트워크
에서 오는 메세지를 받는곳(또는 보내던가).. 뭐 비교하자면

라우터:각각의 호스트(or 라우터)
들을 연결 한다  네트워크 A에서 네트워크 B로 데이터가 이동할려면 반드시  각
네트워크를 관리하는 라우터 끼리 연결이 되어야 한다
HostA->RouterA->RouterD->RouterE->RouterF....->RouterB->HostB
------------------------                                                                   ------------------------
Network A                                                                                    NetworkB


#include<sys/types.h>
#include<sys/socket.h>

sockfd=int socket(int domain,int type,int protocol);
int bind(int sockfd,struct sockaddr *myaddr,int addrlen);
int listen(int sockfd,int backlog);
sockfd2=int accept(int sockfd,struct sockaddr *addr,int *addrlen);
int connect(int sockfg,struct sockaddr *serv_addr,int addrlen);

//구조체 설명은 나중에 한다나 뭐라나..

다음 1-3 파트는 생략. 파일 입출력이므로 ,,,PASS
파트 1은 별루 한것도 없이 그냥 끝~~~~

--------추가 _t 자료형(size_t,time_t,key_t등)-----------
에 대해서는 컴퓨터 비트가 바뀌면서 저장크기(ex int.. 16bit==2 32bit==4)
의차이가 나게 되므로 이런 경우를 줄이기 없애기 위해서 해더파일에서 정의 해 놓은 모양임

'Programming > Networking' 카테고리의 다른 글

gethostbyname 의 세그멘테이션 오류  (2) 2008.02.28
소켓shutdown..DomainName<->IP  (0) 2006.07.18
TCP/IP 추가 and UDP /IP  (0) 2006.07.18
소켓 프로그래밍 part 2~4 TCP/IP  (4) 2006.07.15
prev 1 next