반응형
반응형
반응형

5-1. 에코 클라이언트! TCP 기반에서의 완벽 구현

TCP 기반의 데이터 전송 특징

한 번의 데이터 전송함수 호출이 늘 하나의 패킷을 형성하는 것은 아니다.

※ 버퍼 : 서버 프로그램 상의 문자 배열.

※ ABCD를 클라이언트에서 서버로 보냈지만 A,B,C,D와 같이 패킷이 나누어져서 서버가 클라이언트로 보낼 수 있다. 

※ echo server에서는 클라이언트에서 문제가 된다.

※ 구현 : 클라이언트는 여러번 read(recv)함수를 호출해야 한다. -> for문에서 읽어들인 바이트수가 보낸 바이스만큼 읽을 때까지 반복한다.


패킷이 나누어져 보내지는 이유? 뒤에 밝힘


5-2. 경계가 없는 TCP 기반의 데이터 전송

데이터 송수신 함수의 호출 회수는 큰 의미를 지니지 않는다.

예시) 위의 내용을 증명하기 위한 예제 프로그램

※ 서버에서는 한 번에 메세지를 읽기 위해서 sleep(5);를 한다.

※ 클라이언트에서는 4번에 나누어서 메세지 수신을 하기 위해 sleep(10);을 추가하였다.


이미 전송된 데이터는 어디에 존재하고 있었는가?

예시) 서버가 전송하면 클라이언트 (소켓)버퍼에 서버에서 받은 내용을 저장하고 있다.


서버에서 accept 했을 때 생기는 소켓에서 입력버퍼와 출력버퍼가 생성된다.

클라이언트는 소켓에 입출력버퍼가 있다.

※ read함수는 입력버퍼에 있는 내용을 읽는다. 바로 읽지 못할 수 있기 때문에 버퍼가 존재한다.


출력버퍼의 역할?

※ (서버에서) 송신할 때 (클라이언트의) 입력버퍼보다 큰 양을 보낼 수 없다.

=> 가능한 이유 : 클라이언트가 입력버퍼의 양만큼만 보내라는 신호를 보내기 때문에...

※ 이 이유때문에 출력(송신)버퍼가 필요하다.


※ 흐름제어를 위해서 입출력 버퍼가 존재한다.


TCP 기반의 전송제어

1. 버퍼가 수용할 수 있는 크기 이상의 데이터 전송은 이루어지지 않는다.

2. 따라서 TCP 기반의 데이터 전송 함수는 여러 개의 패킷을 생성하기도 한다.

3. 슬라이딩 윈도우 프로토콜 : 남은 버퍼양만큼만 데이터 전송을 하도록 돕는다.


5-3 TCP의 내부 구조

TCP의 데이터 전송 과정

(서버와 클라이언트는 서로 의견을 존중한다.)


1. 연결 설정 단계

클라이언트가 connect 함수 호출 시 진행

Three-way handshaking

① SYN(C) : 동기화. 싱크. 데이터를 주고 받을 수 있습니까?

② SYN + ACK(S) : 대화가 가능(OK)합니다. SYNchronize(동기화)에 대한 ACKnowgement(확인)의 기능.

③ ACK(C) : 잘 받았다라는 뜻으로 확인한다.

※ ③을 보내야 하는 이유 : 클라이언트가 ACK을 보내지 않으면 서버 입장에서 확인 메세지를 못받았다고 생각한다.


SEQ : 시퀀스 번호. 메세지를 잘 받았는 지 확인하기 위해서 붙이는 번호.

(메세지 번호) 내가 보낸 번호를 ACK으로 대답해 달라.

ACK : 확인 번호. 잘 받았다는 것을 응답하기 위해 붙이는 번호.

다음 SEQ 번호를 보내라는 뜻.


2. 데이터 송수신 단계

서버/클라이언트 간 데이터 송수신 함수 호출 과정에서 진행.

1. SEQ:1301,100바이트를 보낸다.

2. 100바이트를 잘 받았다는 것을 알리기 위해 SEQ번호+100을 해서 ACK을 보낸다.

※ SEQ번호는 응답받은 ACK번호와 같아야 한다.

3. SEQ:1401, 100바이트를 보냈는데 손실되었다. 보내는 동시에 타이머를 작동.

손실되었으므로 응답이 없다. 상대방이 못받았다고 생각하므로

4. SEQ:1401, 100바이트를 다시 보낸다.

5. ACK을 보낸다.


3. 연결 종료 단계

클라이언트 혹은 서버가 close(closesocket) 함수 호출 시 진행

four-way handshaking

1. FIN(A->B) : 종료 요청의 메세지를 담은 패킷을 보낸다. FINish

2. ACK(B->A) : 단순히 패킷을 잘 받았다는 신호만 보낸다. 아직 종료할 상황이라는 뜻은 아니다.

3. FIN(B->A) : 종료해도 좋다는 의미의 FINish를 보낸다.

4. ACK(A->B) : 최종적인 수신 응답 메세지 ACK을 전송한다.

반응형
반응형

4-1 TCP/UDP에 대한 이해

TCP/IP 프로토콜 스택

응용프로그램 계층      : 응용프로그램     응용프로그램

전송(Transport)  계층 :       TCP                UDP

네트워크 (Network)계층:                  IP

데이터링크 계층 :                          LINK

물리 계층 


데이터링크 계층

LAN, WAN, MAN과 같은 네트워크 표준과 관련된 프로토콜의 정의한다.


IP 계층

어떻게 길을 찾아 갈 것인가?

라우터끼리는 (도로사정)이 어떤지 서로 통신하여 패킷을 보낼 최적의 길을 찾는다.

신뢰할 수 없는 프로토콜(데이터가 손실 될 수 있고) 경로가 일정치 않으며 패킷을 보낸 순서도 보장하지 못한다. 비연결 지향 프로토콜이다.


TCP/UDP

(IP 계층을 기반으로 하여 ) 데이터를 어떻게 전송할 것인가?

TCP/UDP(2가지 프로토콜) 중에 원하는 프로토콜을 선택한다.


TCP와 IP의 관계

IP를 기반으로 길을 찾고 TCP를 통해 연결 지향 및 신뢰성 있는 통신을 제공한다.

호스트대 호스트가 어떻게 데이터를 주고 받을 것인지 약속.

IP(편지에 비유) -> 패킷(편지)을 잃어버림


TCP의 역할 

A 호스트가 B 호스트에게 패킷을 하나 전송한다.

1. B가 잘 받았을 경우 : 응답용 패킷을 A에게 전송한다.

2. B가 잘 못 받았을 경우 : A는 B가 데이터를 수신하지 못했다고 간주하고 임의의 시간 후 재전송.


4-2. TCP 기반 서버의 구현

socket - 소켓 생성

bind - 주소할당

listen - 연결 요청 대기 상태 (친구에게 전화가 올 수 있는 상태)

accept - 연결 허용(수화기를 든다.)

read & write - 데이터 송수신

close - 연결 종료


'연결 요청 대기 상태'로의 진입

1. listen 함수는 전달되는 인자의 소켓을 '서버 소켓'이 되게 한다.

2. listen 함수는 backlog의 수(대기실의 크기)만큼 '연결 요청 대기 큐'를 생성 한다.

3. 성공하면 '연결 요청 대기 상태'가 된다.

#include<sys/type.h>

int listen(int s, int backlog);

#include<winsock2.h>

int listen(SOCKET s, int backlog);

 - socket : 서버소켓으로 만들 핸들 혹은 파일 디스크립터.

 - backlog : 대기 큐(실)의 크기, 클라이언트 수.


서버의 역할과 연결요청 대기상태

서버 소켓은 일종의 '문지기'이다. (클라이언트의 연결 요청을 감지하고 받는다.)

클라이언트 - 서버로의 연결요청 - 서버 소켓 -> 대기실

※ 여러 사람의 요청을 받게 하기 위해 '큐(대기실)'를 만든다.


연결요청 수락하기

연결요청 대기 큐에 존재하는 클라이언트의 연결 요청 수락.


#include<sys/type.h>

#include<sys/socket.h>

int accept(int s, struct sockaddr *addr, int *addrlen);

#include<winsock2.h>

SOCKET accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);

리턴값 : 클라이언트와 연결하기 위한 (밑의 그림의)New 소켓

addr : 클라이언트의 주소 정보가 채워진다.

addrlen : 정보구조체의 크기 정보가 채워진다.

 

listen ~ accept 과정

※ New 소켓은 자동적으로 만들어지며 이 New 소켓으로 클라이언트와 데이터 송수신이 가능하다.


4-3 TCP 기반 클라이언트의 구현


#include<sys/types.h>

#include<sys/socket.h>

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

sockfd : 연결 요청을 할 소켓

serv_addr : 주소정보

addrlen : 구조체 크기


※ 소켓은 연결하기 전에 미리 운영체제(커널)에 의해 임의로 할당된다.


4-4 서버/클라이언트 함수 호출 관계




※ listen()에서 대기 큐를 만들고 연결 요청을 받을 수 있는 서버 소켓을 만든다.

※ connect 함수는 서버의 IP, 포트를 설정해 주면 자동으로 클라이언트 컴퓨터 내의 임의의 포트에 운영체제가 통신하기 위한 소켓을 생성한다.

※ accept() 함수는 연결 요청 대기 큐가 비어있을 때까지 혹은 클라이언트가 연결할 때까지 block되어 있다.

=> 리턴 되면서 연결된다.


4-5 Iterative 서버의 구현

Iterative 서버 : 반복해서 클라이언트의 요청을 처리한다.

여러 클라이언트가 서버로 연결 요청을 한다. -> 연결 요청 대기 큐로 들어간다. -> 서버가 accept를 호출할 때마다 대기 큐에서 하나의 소켓을 꺼낸다. -> 그 소켓과 통신을 하고 끝나면 반복해서(Iterative) accept를 호출한다. 


Iterative Server Template

※ 리턴 클라이언트 소켓은 하나다.


4-6 에코(echo) 서버/클라이언트의 구현

concurrent 서버(서버 하나와 클라이언트 여러 개 관계)

※ 버퍼 : 여기서는 프로그램 상의 버퍼. 문자열을 저장할 수 있는 배열.

※ 클라이언트에서 close(소켓핸들);을 호출하면 서버의 read함수의 리턴 값은 0이 된다.

반응형
반응형

3-1 Internet Address

IP(Internet Address) 

인터넷에 존재하는 호스트들을 구분하기 위한 32비트 주소 체계

점이 찍힌 십진수 표현 방식(Dotted-decimal Notation) : 211.217.10.9


클래스

Class A : 0.0.0.0 ~ 127.255.255.255, 1바이트는 네트워크 ID, 3바이트는 호스트 ID

Class B : 128.0.0.0 ~ 191.255.255.255, 2바이트는 네트워크 ID, 2바이트는 호스트 ID

Class C : 192.0.0.0 ~ 223.255.255.255, 3바이트는 네트워크 ID, 1바이트는 호스트 ID

Class D : 멀티캐스트 주소. 224.0.0.0 ~ 239.255.255.255

Class E : 예약됨. 240.0.0.0 ~ 255.255.255.255


IP 주소 : 네트워크 주소(네트워크를 구분지음) + 호스트 주소(호스트를 구분지음)

subnet mask에 따라서 네트워크 주소(ID)와 호스트 주소(ID)로 나누어진다.


※ 라우터는 네트워크 ID(주소)만 참조한다.

※ 루프백 주소 : 127.x.x.x, 네트워크 상으로 패킷을 전송하지 않고 자기자신에게 돌려준다.


3-2 Port란 무엇인가?

Port

호스트 내에서 실행되고 있는 프로세스를 구분 짓기 위한 16비트의 논리적인 값. (소켓에 할당)

논리적인 값 : 소프트웨어 적으로 구현. 

Well-known ports : 0~1023


3-3 주소 정보의 표현

IPV4의 주소 체계를 나타내는 구조체

※ 하나의 프로토콜 내에 2개 이상 프로토콜이 있을 것을 대비해서 만든 구조체. ()는 윈도우즈용.

※ 모든 데이터는 네트워크 바이트 순서로 저장해야 한다.

struct sockaddr_in

{

sa_family_t(short) sin_family; // 주소 체계(address_family) - AF_INET

uint16_t(unsigned short) sin_port; // 16비트 TCP 혹은 UDP 포트

struct in_addr sin_addr; // 32비트 IPv4 주소

char  sin_zero[8]; // 사용되지 않음. padding 용도

};


struct in_addr

{

uint32_t(unsigned long) s_addr; // 32비트 IPv4 인터넷 주소

};



3-4 네트워크 바이트 순서

0x12345678을 Big-Endian으로는 메모리 순서대로 0번지 0x12, 1번지 0x34, 2번지 0x56, 3번지 0x78

0x12345678을 Little-Endian으로는 메모리 순서대로 0번지 0x78, 1번지 0x56, 2번지 0x34, 3번지 0x12

형태로 저장.


호스트 바이트 순서 

어떤 시스템(motorola, sun사 기계)은 Big-Endian, 어떤 시스템(intel사)은 Little-Endian을 사용하므로 일정하지 않다.

※ 데이터 표현 방식이 다르므로 다른 플랫폼끼리 문제가 발생한다.


네트워크 바이트 순서

Big-Endian 방식을 적용하기로 하였다.


바이트 순서 변환 함수

※ 어느 시스템에서 돌아갈 지 모르기 때문에 반드시 사용해야 한다.

unsigned short htons(unsigned short); // 호스트 -> 네트워크 short

unsigned short ntohs(unsigned short); // 네트워크 -> 호스트 short

unsigned long htonl(unsigned long); // 호스트 -> 네트워크 long

unsigned long ntohl(unsigned long); // 네트워크 -> 호스트 long


'h' : host byte order

'n' : network byte order

's' : short(16비트)

'l' : long(32비트)


3-5 인터넷 주소 조작하기

1. 점이 찍힌 십진수 방식(Dotted-Decimal Notation)을 Big-Endian 32비트 정수형 데이터로 바꿔주는 함수(네트워크)

#include<sys/socket.h>

#include<netinet/in.h>

#include<arpa/inet.h>

unsigned long inet_addr(const char *string);

리턴 : 성공시 32비트 big-endian값, 실패시 INADDR_NONE


#include<sys/socket.h>

#include<netinet/in.h>

#include<arpa/inet.h>

int inet_aton(const char* string, struct in_addr *addr);
리턴 : 성공시 true, 실패시 false
※ 바로 struct in_addr에 값을 제공할 수 있다.


2. Big-Endian 32비트 정수형 데이터를 점이 찍힌 십진수 방식로 바꿔주는 함수(네트워크)

#include<sys/socket.h>

#include<netinet/in.h>

#include<arpa/inet.h>

char* inet_ntoa(struct in_addr addr);

※ 따로 inet_ntoa 내부적으로 static 배열을 통해 주소에 대한 문자열이 존재한다.


3-6 인터넷 주소 초기화

struct sockaddr_in addr;

char *serv_ip = "...";

char *serv_port = "...";

memset(&addr, 0, sizeof(addr_len)); // 주소에 해당하는 구조체 값을 0으로 초기화. 좋은 습관.

addr.sin_family = AF_INET;

addr.sin_addr.s_addr = inet_addr(serv_ip);

addr.sin_port = htons(atoi(serv_port));


INADDR_ANY?

addr.sin_addr.s_addr = htons(INADDR_ANY);

// 서버의 IP가 뭐더라? 답은 INADDR_ANY : 내 시스템의 IP 주소를 찾아 알아서 할당.


3-7 주소 정보 할당하기

리눅스

#include<sys/types.h>

#include<sys/socket.h>

int bind(int sockfd, struct sockaddr *myaddr, int addrlen);

윈도우즈

#include<winsock2.h>

int bind(SOCKET s, const struct sockaddr FAR *name, int namelen);


sockfd/s : 주소를 할당하고자 하는 소켓의 파일 디스크립터 인자/핸들 인자

myaddr : 할당하기를 원하는 주소 정보를 지닌 sockaddr_in 구조체 변수의 포인터. 

※ sockaddr 형태로 형변환 해서 넘겨야 한다. 

※ 프로토콜에 독립적으로 사용하기 위해서. void 포인터 보다 먼저 이 함수가 개발되었다. 

※ FAR 포인터는 과거의 잔재. 현재는 무시한다.

addrlen/namelen : 주소 정보 구조체의 길이.


3-8 윈도우즈 기반으로 구현하기

※ SOCKADDR_IN = struct sockaddr_in

※ SOCKADDR = struct sockaddr

※ 서버 프로그래밍을 할 때는 htons(INADDR_ANY);를 사용한다.


3-9 WSAStringToAddress & WSAAddressToString

주소 정보를 나타내는 문자열을 가지고 주소 정보 구조체 변수를 채운다.

※ 윈도우즈 기반 주소 변환 함수.

#include<winsock2.h>

INT WSAStringToAddress(

LPTSTR AddressString, // 점이 찍힌 십진수 표현(포트정보 포함)과 같은 주소 정보 문자열 포인터.

INT AddressFamily,      // 주소 정보 문자열이 속한 주소 체계(AF_INET)

LPWSAPROTOCOL_INFO lpProtocolInfo,   // 프로토콜 제공자를 설정. 일반적으로 NULL.

LPSOCKADDR lpAddress,  // 주소 정보 구조체 변수 포인터

LPINT lpAddressLength);  // lpAddress 포인터가 가리키는 버퍼의 크기.

리턴 : 성공시 0, 실패시 SOCKET_ERROR


#include<winsock2.h>

INT WSAAddressToString(

LPSOCKADDR lpsaAddress, // 문자열로 변환할 주소 정보를 가진 구조체 포인터

dwAddressLength,              // lpsaAddress 포인터가 가리키는 변수의 크기

LPWSAPROTOCOL_INFO lpProtocolInfo,   // 프로토콜 제공자를 설정. 일반적으로 NULL.

LPTSTR lpszAddressString,  // 문자열로 변경된 결과를 저장할 버퍼 포인터.

LPDWORD lpdwAddressStringLength);     // lpszAddressString 버퍼의 크기.

리턴 : 성공시 0, 실패시 SOCKET_ERROR




반응형
반응형

2-1 프로토콜 

컴퓨터 상호간의 대화에 필요한 통신 규약

혼돈의 여지가 있으면 안되고 잘 정의(FM)되어야 한다.

※ 안 좋은 예 : 서버에서 accept 하자마자 읽는 연산을 수행.


2-2 소켓의 생성

기본적인 통신 도구

프로토콜에 독립적 : 사용자가 프로토콜을 정해주어야 한다는 점에서...

데이터 전송 형태(타입)를 지정해야 한다.


2-3 프로토콜 체계

#include<sys/types.h>

#include<sys/socket.h>

int socket(int domain, int type, int protocol);

domain : 프로토콜 체계. family

(여러 가지 프로토콜이 합쳐져서 체계를 이룬다.)

PF_INET : IPv4 (4바이트 2^32승개의 IP)

PF_INET6 : IPv6 (16바이트 2^128승개의 IP, 약 10의 38승)

PF_LOCAL : Local 통신을 위한 UNIX 프로토콜

PF_PACKET : Low level socket을 위한 인터페이스

PF_IPX : IPX 노벨 프로토콜

※ 127.0.0.1 : loopback address


2-4 소켓의 타입

type : 형태

1. 연결지향형(connection oriented) 

전송하는 순서대로 데이터가 전달.

에러나 데이터 오류 없이 전달.

전송되는 데이터의 경계가 존재하지 않는다.

 => write함수를 2번호출한다고 해서 read함수가 꼭 2번 호출될 필요가 없다. 


2. 비연결지향형(connectionless)

예시) 우편이면 일반우편, 빠른 우편, 등기 등.

전송되는 순서에 상관없이 가장 빠른 전송.

데이터는 손실되고 에러가 발생할 수도 있다.

데이터의 경계가 존재하고 그 크기는 제한되어 있다.

 => write함수를 2번 호출하면 read함수가 꼭 2번 호출해야 한다.


2-5. 프로토콜의 선택

protocol : 프로토콜을 구체화할 때 필요하다. (raw_socket을 다룰 때 유용하다.)

IPPROTO_TCP : TCP를 기반으로 하는 소켓을 생성. PF_INET + SOCK_STREAM

IPPROTO_UDP : UDP를 기반으로 하는 소켓을 생성. PF_INET + SOCK_DGRAM


※ 파일 핸들도 정수형 데이터이다. 

int a = socket(...); = SOCKET a = socket(...);

앞으로 소켓의 데이터 형이 바뀔 것을 대비해서 SOCKET을 사용하는 것이 좋다.


소켓의 종료

리눅스 

#include<unistd.h>

int close(int filedes);

리턴 : 성공시 0, 실패시 -1

filedes : 닫아줄 파일의 파일 디스크립터


#include<winsock2.h>

int closesocket(SOCKET s);

리턴 : 성공시 0, 실패시 SOCKET_ERROR

s : 닫아줄 소켓의 핸들

반응형
반응형

1-1. 네트워크 프로그래밍의 이해

네트워크 : 호스트(End-system)들을 연결하는 시스템

호스트 : PC, workstation, PDA

인터넷 : 멀리 떨어진 둘 이상의 네트워크가 연결되 이뤄진 거대한 네트워크 -> 라우터 : 이기종 네트워크를 연결하는 장비


1.2 소켓 이해하기

클라이언트/서버 모델

기계 아님. 

서버 : 연결 요청을 기다린다.

 - Iterative(반복적인) Server : 한 순간에 하나의 클라이언트에게 응담

 - Concurrent Server : 동시에 여러 클라이언트에게 응답한다.

클라이언트 : 서버에 요청하고 응답을 기다리는 호스트.


네트워크 프로그래밍

네트워크로 연결된 두 호스트 간의 데이터 송수신

소켓 : 원격에 존재하는 두 호스트를 연결시켜 주는 매개체. 운영체제에서 제공한다.

(소켓을 꽂으면 전원을 받는다.)


서버 소켓(리눅스 함수)

소켓 생성(전화기 구입) - socket


#include<sys/types.h>

#include<sys/socket.h>

int socket(int domain, int type, int protocol);

리턴 : 성공시 파일 디스크립터 실패시 -1


IP 주소, 포트 할당(전화번호 할당) - bind

#include<sys/socket.h>

int bind(int sockfd, struct sockaddr *myaddr, int addrlen);

리턴 : 성공시 0, 실패시 -1


연결 요청 대기 상태(케이블에 연결) - listen

#include<sys/socket.h>

int listen(int sockfd, int backlog);

리턴 : 성공시 0, 실패시 -1


연결 수락(수화기를 든다) - accept

#include<sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, int *addrlen);

리턴 : 성공시 파일 디스크립터 실패시 -1


클라이언트 소켓

소켓 생성(전화기 구입) - socket


연결 요청(전화 걸기) - connect

int connect(int sockfd, struct sockaddr *addr, int addrlen);

리턴 : 성공시 0, 실패시 -1


리눅스 프로그램 컴파일(링크) 하는 법 : gcc ?.c -o ?

실행하는 법 : ./?

※ 로컬 컴퓨터의 IP : 127.0.0.1

※ 당연히 서버부터 수행한다.


1.3 파일 조작하기

리눅스에서는 모든 것(소켓등)을 파일로 간주한다.

파일의 생성, 삭제, 데이터 입력 및 출력.

관리는 운영체제가 한다.


저수준 파일 입출력 

저수준은 시스템이 직접 제공해 준다는 뜻.

표준입력 : 기본은 키보드, fd 0번

표준출력 : 기본은 모니터, fd 1번

표준에러출력 : 기본은 모니터, 버퍼가 없음. fd 2번

※ 전송은 출력, 수신은 입력은 같은 의미.

※ 표준입출력함수 : ANSI 표준에서 제공해 주는 함수. printf, scanf등...


파일 디스크립터(file descriptor) 

시스템이 만든 것을 가리키기 좋게 하기(포인터) 위해 시스템이 사용자에게 건내주는 숫자값

윈도우의 핸들과 비슷.

모든 파일을 관리하기 위해 운영체제에서 파일 디스크립터를 할당한다.

※ 파일 디스크립터는 redirection가능.


파일 열기

#include <fcntl.h>

#include<sys/types.h>

#include<sys/stat.h>


int open(const char *path, int flag);

리턴 : 성공시 파일 디스크립터, 실패시 -1

path : 파일에 대한 경로

flag : 모드 설정. |(bit wise)를 통해 연산가능.

O_CREAT : 파일이 없을 때 파일 생성. 

O_TRUNC : 파일이 있다면 새로 생성.

O_RDONLY : 읽기 전용 모드


파일 닫기

#include<unistd.h>

int close(int filedes);

리턴 : 성공시 0, 실패시 -1

filedes : 닫아줄 파일의 파일 디스크립터


데이터 쓰기

#include<unistd.h>

ssize_t write(int filedes, const void * buf, size_t nbytes);

filedes : 데이터 전송 영역의 파일 디스크립터.

buf : 전송할 데이터를 가지고 있는 버퍼(데이터)의 포인터. 

nbytes : 전송할 데이터의 바이트수.

ssize_t = signed int, size_t = unsigned int

※ 타입이름을 새로 정의하는 이유는 다른 시스템에서 실행시키기 위해(코드 확장성)

=> 소스 코드를 바꾸지 않고 컴파일만 다시 하면 새로운 시스템에서 잘 돌아간다.


데이터 읽기

#include<unistd.h>

ssize_t read(int filedes, void *buf, size_t nbytes);

filedes : 데이터를 수신 받을 대상을 가리키는 파일 디스크립터.

buf : 수신한 데이터를 저장할 버퍼의 포인터

nbytes : 수신할 최대 바이트수.


1-4 윈도우즈 기반으로 구현하기

WinSock을 위한 헤더 및 라이브러리 설정.

1. #include<winsock2.h>

2. #pragma comment(lib,ws2_32.lib)

ws2_32.lib을 위와 같이 라이브러리를 링크

3. winsock 라이브러리 초기화(standby) 및 해제(리소스 반환)


Winsock 초기화하기

#include<winsock2.h>

int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

wVersionRequested : 프로그램에서 요구하는 winsock 최상위 버젼을 알려준다.

WORD : 16비트 unsigned int

예) Version 3.4 = MAKEWORD(3 /*주버젼*/,4 /*부버젼*/) =  0x0403 

lpWSAData : WSADATA 타입의 변수 포인터.


Winsock 해제하기

#include<winsock2.h>

int WSACleanup();


기본적인 Template

int main(int argc, char **argv)

{

    WSADATA wsaData;

    if(WSAStartup(MAKEWORD(2,2), &wsaData) !=0)

         error_handling("WSAStartup() error!");

    ...

    WSACleanup();

    return 0;

}


소켓의 생성

#include<winsock2.h>

SOCKET socket(int af, int type, int protocol);

리턴 : (정수형 데이터 타입)성공시 소켓 핸들, 실패시 INVALID_SOCKET 리턴.


주소와 포트 할당

#include<winsock2.h>

int bind(SOCKET s, const struct sockaddr FAR *name, int namelen);

리턴 : 성공시 0, 실패시 SOCKET_ERROR


연결요청대기상태로의 진입

#include<winsock2.h>

int listen(SOCKET s, int backlog);

리턴 : 성공시 0, 실패시 SOCKET_ERROR


연결 수락

#include<winsock2.h>

SOCKET accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);

리턴 : (정수형 데이터 타입)성공시 소켓 핸들, 실패시 INVALID_SOCKET 리턴.


연결 요청

#include<winsock2.h>

int connect(SOCKET s, const struct sockaddr FAR *name, int namelen);

리턴 : (정수형 데이터 타입)성공시 소켓 핸들, 실패시 INVALID_SOCKET 리턴.


데이터 출력

#include<winsock2.h>

int send(SOCKET s, const char FAR *buf, int len, int flags);

리턴 : 성공시 전송한 바이트 수, 실패시 SOCKET_ERROR

s : 전송할 호스트에 연결된 소켓의 핸들

buf : 전송할 데이터를 저장하고 있는 버퍼의 포인터

len : 전송할 바이트 수를 인자로 전달

flags : 여러가지 옵션을 설정.


데이터 입력

#include<winsock2.h>

int recv(SOCKET s, char FAR *buf, int len, int flags);

리턴 : 성공시 수신한 바이트 수, 실패시 SOCKET_ERROR

s : 수신할 영역을 나타내는 소켓의 핸들.

buf : 수신할 데이터를 저장한 버퍼의 포인터

len : 수신할 최대 바이트수

flags : 여러가지 옵션을 설정.


※ 리눅스에도 send, recv함수가 있지만 리눅스에서는 소켓도 파일로 처리한다는 것을 강조하기 위해 read, write함수를 사용하였고 윈도우즈에서는 read, write함수가 없기 때문에 send, recv함수로 소켓 입출력을 수행한다.

반응형

+ Recent posts