Study: ComputerScience(CS)/CS: Network

[Network] Socket μ†ŒμΌ“ ν”„λ‘œκ·Έλž˜λ° (feat. sockaddr_in, IPv4...)

DrawingProcess 2022. 12. 16. 22:04
λ°˜μ‘ν˜•
πŸ’‘ λ³Έ λ¬Έμ„œλŠ” 'Socket μ†ŒμΌ“ ν”„λ‘œκ·Έλž˜λ°'에 λŒ€ν•΄ 정리해놓은 κΈ€μž…λ‹ˆλ‹€.
C/C++μ—μ„œ "sys/socket.h"을 μ‚¬μš©ν•˜μ—¬ μ†ŒμΌ“ ν”„λ‘œκ·Έλž˜λ°ν•˜λŠ” 방법에 λŒ€ν•΄ μ •λ¦¬ν•˜μ˜€μœΌλ‹ˆ μ°Έκ³ ν•˜μ‹œκΈ° λ°”λžλ‹ˆλ‹€.

1.  μ†ŒμΌ“ ν†΅μ‹ μ΄λž€?

1.1 μ†ŒμΌ“(Socket) μ΄λž€?

μ†ŒμΌ“(Socket)은 ν”„λ‘œμ„ΈμŠ€κ°€ λ„€νŠΈμ›Œν¬ μ„Έκ³„λ‘œ 데이터λ₯Ό λ‚΄λ³΄λ‚΄κ±°λ‚˜ ν˜Ήμ€ κ·Έ μ„Έκ³„λ‘œλΆ€ν„° 데이터λ₯Ό λ°›κΈ° μœ„ν•œ μ‹€μ œμ μΈ 창ꡬ 역할을 ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ ν”„λ‘œμ„ΈμŠ€κ°€ 데이터λ₯Ό λ³΄λ‚΄κ±°λ‚˜ λ°›κΈ° μœ„ν•΄μ„œλŠ” λ°˜λ“œμ‹œ μ†ŒμΌ“μ„ μ—΄μ–΄μ„œ μ†ŒμΌ“μ— 데이터λ₯Ό μ¨λ³΄λ‚΄κ±°λ‚˜ μ†ŒμΌ“μœΌλ‘œλΆ€ν„° 데이터λ₯Ό 읽어듀여야 ν•©λ‹ˆλ‹€.

μ†ŒμΌ“μ€μ€ ν”„λ‘œν† μ½œ, IP μ£Όμ†Œ, 포트 λ„˜λ²„λ‘œ μ •μ˜λ©λ‹ˆλ‹€.
 
  • ν”„λ‘œν† μ½œ(protocol): μ›λž˜ μ™Έκ΅μƒμ˜ μ–Έμ–΄λ‘œμ¨ μ˜λ‘€λ‚˜ ꡭ가간에 약속을 μ˜λ―Έν•˜λ©°, ν†΅μ‹ μ—μ„œλŠ” μ–΄λ–€ μ‹œμŠ€ν…œμ΄ λ‹€λ₯Έ μ‹œμŠ€ν…œκ³Ό 톡신을 μ›ν™œν•˜κ²Œ μˆ˜μš©ν•˜λ„λ‘ ν•΄μ£ΌλŠ” 톡신 κ·œμ•½μž…λ‹ˆλ‹€.
  • IP: μ „ 세계 컴퓨터에 λΆ€μ—¬λœ 고유의 식별 μ£Όμ†Œ
  • 포트(port): λ„€νŠΈμ›Œν¬ μƒμ—μ„œ ν†΅μ‹ ν•˜κΈ° μœ„ν•΄μ„œ 호슀트 λ‚΄λΆ€μ μœΌλ‘œ ν”„λ‘œμ„ΈμŠ€κ°€ ν• λ‹Ήλ°›μ•„μ•Ό ν•˜λŠ” κ³ μœ ν•œ μˆ«μžμž…λ‹ˆλ‹€. ν•œ 호슀트 λ‚΄μ—μ„œ λ„€νŠΈμ›Œν¬ 톡신을 ν•˜κ³  μžˆλŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό μ‹λ³„ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ˜λŠ” κ°’μ΄λ―€λ‘œ, 같은 호슀트 λ‚΄μ—μ„œ μ„œλ‘œ λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€κ°€ 같은 포트 λ„˜λ²„λ₯Ό κ°€μ§ˆ 수 μ—†λ‹€. 즉, 같은 컴퓨터 λ‚΄μ—μ„œ ν”„λ‘œκ·Έλž¨μ„ μ‹λ³„ν•˜λŠ” λ²ˆν˜Έμž…λ‹ˆλ‹€.

λ‹€μ‹œλ§ν•΄ μ†ŒμΌ“μ΄μ€ λ–¨μ–΄μ Έ μžˆλŠ” 두 호슀트λ₯Ό μ—°κ²°ν•΄μ£ΌλŠ” λ„κ΅¬λ‘œμ¨ μΈν„°νŽ˜μ΄μŠ€μ˜ 역할을 ν•˜λŠ”λ° 데이터λ₯Ό μ£Όκ³  받을 수 μžˆλŠ” ꡬ쑰체둜 μ†ŒμΌ“μ„ 톡해 데이터 ν†΅λ‘œκ°€ λ§Œλ“€μ–΄ μ§‘λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ†ŒμΌ“μ€ 역할에 따라 μ„œλ²„ μ†ŒμΌ“, ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“μœΌλ‘œ κ΅¬λΆ„λ©λ‹ˆλ‹€.

1.2 μ†ŒμΌ“ν†΅μ‹ μ˜ 흐름

1.2.1 μ„œλ²„ (Server)

ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“μ˜ μ—°κ²° μš”μ²­μ„ λŒ€κΈ°ν•˜κ³ , μ—°κ²° μš”μ²­μ΄ 였면 ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“μ„ μƒμ„±ν•˜μ—¬ 톡신이 κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€.

  1. socket() ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ μ†ŒμΌ“μ„ 생성
  2. bind() ν•¨μˆ˜λ‘œ ip와 port 번호λ₯Ό μ„€μ •
  3. listen() ν•¨μˆ˜λ‘œ ν΄λΌμ΄μ–ΈνŠΈμ˜ μ ‘κ·Ό μš”μ²­μ— μˆ˜μ‹  λŒ€κΈ°μ—΄μ„ λ§Œλ“€μ–΄ λͺ‡ 개의 ν΄λΌμ΄μ–ΈνŠΈλ₯Ό λŒ€κΈ° μ‹œν‚¬μ§€ κ²°μ •
  4. accept() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ ν΄λΌμ΄μ–ΈνŠΈμ™€μ˜ 연결을 κΈ°λ‹€λ¦Ό

1.2.2 ν΄λΌμ΄μ–ΈνŠΈ (Client)

 
μ‹€μ œλ‘œ 데이터 μ†‘μˆ˜μ‹ μ΄ μΌμ–΄λ‚˜λŠ” 것은 ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“μž…λ‹ˆλ‹€.
 
  1. socket() ν•¨μˆ˜λ‘œ κ°€μž₯λ¨Όμ € μ†ŒμΌ“μ„ μ—°λ‹€.
  2. connect() ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ 톡신 ν•  μ„œλ²„μ˜ μ„€μ •λœ ip와 port λ²ˆν˜Έμ— 톡신을 μ‹œλ„
  3. 톡신을 μ‹œλ„ μ‹œ, μ„œλ²„κ°€ accept() ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ ν΄λΌμ΄μ–ΈνŠΈμ˜ socket descriptorλ₯Ό λ°˜ν™˜
  4. 이λ₯Ό 톡해 ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„κ°€ μ„œλ‘œ read(), write() λ₯Ό ν•˜λ©° 톡신 (이 과정이 반볡)

1.3 μ†ŒμΌ“μ’…λ₯˜

1.3.1 TCP 방식: 슀트림(STREAM)

  • μ–‘λ°©ν–₯으둜 λ°”μ΄νŠΈ μŠ€νŠΈλ¦Όμ„ 전솑, μ—°κ²° 지ν–₯μ„±
  • 였λ₯˜ μˆ˜μ •, μ •μ†‘μ²˜λ¦¬, νλ¦„μ œμ–΄ 보μž₯
  • μ†‘μ‹ λœ μˆœμ„œμ— 따라 μ€‘λ³΅λ˜μ§€ μ•Šκ²Œ 데이터λ₯Ό μˆ˜μ‹  → μ˜€λ²„ν—€λ“œκ°€ λ°œμƒ
  • μ†ŒλŸ‰μ˜ 데이터보닀 λŒ€λŸ‰μ˜ 데이터 전솑에 적합 → TCPλ₯Ό μ‚¬μš©

1.3.2 UDP 방식: λ°μ΄ν„°κ·Έλž¨(DGRAM)

  • λΉ„μ—°κ²°ν˜•μ†ŒμΌ“
  • λ°μ΄ν„°μ˜ 크기에 μ œν•œμ΄ 있음
  • ν™•μ‹€ν•˜κ²Œ 전달이 보μž₯λ˜μ§€ μ•ŠμŒ, 데이터가 손싀돼도 였λ₯˜κ°€ λ°œμƒν•˜μ§€ μ•ŠμŒ
  • μ‹€μ‹œκ°„ λ©€ν‹°λ―Έλ””μ–΄ 정보λ₯Ό μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ 주둜 μ‚¬μš© ex) μ „ν™”

1.4 HTTP 톡신과 SOCKET ν†΅μ‹ μ˜ 비ꡐ

1.4.1 HTTP 톡신

  • Client의 μš”μ²­(Request)이 μžˆμ„ λ•Œλ§Œ μ„œλ²„κ°€ 응닡(Response)ν•˜μ—¬ ν•΄λ‹Ή 정보λ₯Ό μ „μ†‘ν•˜κ³  κ³§λ°”λ‘œ 연결을 μ’…λ£Œν•˜λŠ” 방식

1.4.2 HTTP ν†΅μ‹ μ˜ νŠΉμ§•

  • Clientκ°€ μš”μ²­μ„ λ³΄λ‚΄λŠ” κ²½μš°μ—λ§Œ Serverκ°€ μ‘λ‹΅ν•˜λŠ” 단방ν–₯ 톡신
  • Serverλ‘œλΆ€ν„° 응닡을 받은 ν›„μ—λŠ” 연결이 λ°”λ‘œ μ’…λ£Œ
  • μ‹€μ‹œκ°„ 연결이 μ•„λ‹ˆκ³ , ν•„μš”ν•œ κ²½μš°μ—λ§Œ Server둜 μš”μ²­μ„ λ³΄λ‚΄λŠ” 상황에 유용
  • μš”μ²­μ„ 보내 Server의 응닡을 κΈ°λ‹€λ¦¬λŠ” μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ κ°œλ°œμ— 주둜 μ‚¬μš©

1.4.3 SOCKET 톡신

  • Server와 Clientκ°€ νŠΉμ • Portλ₯Ό 톡해 μ‹€μ‹œκ°„μœΌλ‘œ μ–‘λ°©ν–₯ 톡신을 ν•˜λŠ” 방식

1.4.4 SOCKET ν†΅μ‹ μ˜ νŠΉμ§•

  • Server와 Clientκ°€ 계속 연결을 μœ μ§€ν•˜λŠ” μ–‘λ°©ν–₯ 톡신
  • Server와 Clientκ°€ μ‹€μ‹œκ°„μœΌλ‘œ 데이터λ₯Ό μ£Όκ³ λ°›λŠ” 상황이 ν•„μš”ν•œ κ²½μš°μ— μ‚¬μš©
  • μ‹€μ‹œκ°„ λ™μ˜μƒ Streamingμ΄λ‚˜ 온라인 κ²Œμž„ λ“±κ³Ό 같은 κ²½μš°μ— 자주 μ‚¬μš©

2. μ†ŒμΌ“ 톡신에 μ“°μ΄λŠ” ꡬ쑰체

λ¦¬λˆ…μŠ€/μœ λ‹‰μŠ€ μ‹œμŠ€ν…œμ—μ„œλŠ” μ†ŒμΌ“(socket)의 톡신 λŒ€μƒμ„ μ§€μ •ν•˜κΈ° μœ„ν•΄ 'μ£Όμ†Œ(address)'λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. 이 'μ£Όμ†Œ' λΌλŠ” 것을 μ €μž₯ν•˜κ±°λ‚˜ ν‘œν˜„ν•˜λŠ”λ° μ‚¬μš©ν•˜λŠ” ꡬ쑰체가 'sockaddr' μž…λ‹ˆλ‹€.

2.0 ν•„μš”ν•œ 헀더 파일

μ†ŒμΌ“ ν”„λ‘œκ·Έλž˜λ°μ„ μœ„ν•΄ ν•„μš”ν•œ ν—€λ”νŒŒμΌμ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. ν•΄λ‹Ή 헀더 νŒŒμΌμ— 이후 μ„€λͺ…ν•  ꡬ쑰체와 ν•¨μˆ˜λ“€μ΄ κ΅¬ν˜„λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> // μœ„λ₯Ό λͺ¨λ‘ 포함

2.1 sockaddr ꡬ쑰체

μ†ŒμΌ“μ„ 톡해 μ—¬λŸ¬ ν˜•νƒœμ˜ λ„€νŠΈμ›Œν¬λ₯Ό 거의 λΉ„μŠ·ν•œ λ°©μ‹μœΌλ‘œ 데이터λ₯Ό κ΅ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. sockaddrλŠ” μΌμ’…μ˜ 좔상 클래슀처럼 μ†ŒμΌ“μœΌλ‘œ ν†΅μ‹ ν•˜κΈ° μœ„ν•œ μ—¬λŸ¬ λ„€νŠΈμ›Œν¬μ˜ μƒμœ„ κ΅¬μ‘°μ²΄μž…λ‹ˆλ‹€. sockaddr μ•„λž˜ 인터넷망을 μ‚¬μš©ν•΄ ν†΅μ‹ ν•˜λŠ” ꡬ쑰체인 sockaddr_inκ³Ό μœ λ‹‰μŠ€ μš΄μ˜μ²΄μ—μ„œ ν”„λ‘œμ„ΈμŠ€κ°„ 톡신을 μœ„ν•΄ μ‚¬μš©λ˜λŠ” sockaddr_un의 ꡬ쑰체가 μ„ μ–Έλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

 /* sockaddr ꡬ쑰체 */
struct sockaddr {
	sa_family_t sa_family;
	char sa_data[14];
};
  • sa_family: μ†ŒμΌ“μ΄ μ‚¬μš©λ˜λŠ” λ„€νŠΈμ›Œν¬μ˜ μ’…λ₯˜μž…λ‹ˆλ‹€. λ‹€μŒ κ°’ 쀑 ν•˜λ‚˜κ°€ 올 수 μžˆμŠ΅λ‹ˆλ‹€.
    • AF_INET: IPv4λ₯Ό μ‚¬μš©ν•˜λŠ” μΈν„°λ„·λ§μ— μ ‘μ†ν•©λ‹ˆλ‹€.
    • AF_INET6: IPv6λ₯Ό μ‚¬μš©ν•˜λŠ” 인터넷망에 μ ‘μ†ν•©λ‹ˆλ‹€.
    • AF_LOCAL: μœ λ‹‰μŠ€ μš΄μ˜μ²΄μ œμ—μ„œ ν”„λ‘œμ„ΈμŠ€κ°„ 톡신을 μˆ˜ν–‰ν•©λ‹ˆλ‹€.
  • sa_data: sa_family값에 λ”°λ₯Έ μ΅œλŒ€ 14λ°”μ΄νŠΈμ˜ λΆ€κ°€ μ •λ³΄μž…λ‹ˆλ‹€. 이 ν•„λ“œμ˜ λ‚΄μš©μ€ sockaddr_inκ³Ό sockaddr_unμ—μ„œ κ΅¬μ²΄ν™”λ©λ‹ˆλ‹€.

2.2 sockaddr_in ꡬ쑰체

in은 internet의 μ•žκΈ€μžμž…λ‹ˆλ‹€. μ†ŒμΌ“μ„ 톡해 인터넷 망에 μ ‘μ†ν•˜κΈ° μœ„ν•œ κ΅¬μ‘°μ²΄μž…λ‹ˆλ‹€. AF_INET λͺ¨λ“œμ—μ„œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

/* sockaddr_in ꡬ쑰체 */
struct sockaddr_in {
	sa_family_t sin_family; // = 항상 AF_INET
	uint16_t sin_port;
	struct in_addr sin_addr;
	char sin_zero[8];
};

struct in_addr {
	uint32_t s_addr;
};
  • sin_family: sockaddr의 sa_family와 κ°™μŠ΅λ‹ˆλ‹€.
  • sin_port: 톡신을 μœ„ν•΄ μ‚¬μš©ν•  포트 λ²ˆν˜Έμž…λ‹ˆλ‹€.
  • sin_addr: 접속할 λŒ€μƒ(μƒλŒ€λ°©)의 IP μ£Όμ†Œμž…λ‹ˆλ‹€. μžλ£Œν˜•μΈ in_addr κ΅¬μ‘°μ²΄λŠ” Internet Address의 μ€„μž„ ν‘œν˜„μœΌλ‘œ 4λ°”μ΄νŠΈ IP μ£Όμ†Œλ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
  • sin_zero: sockaddrμ—μ„œ sa_dataλ₯Ό 톡해 ν™•λ³΄ν•œ 14λ°”μ΄νŠΈ μ™Έ λ‚˜λ¨Έμ§€ κ³΅κ°„μž…λ‹ˆλ‹€. 항상 0이며 μ‚¬μš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

2.3 sockaddr_in6 ꡬ쑰체

AF_INET6 (IPv6)λ₯Ό μ‚¬μš©ν•˜λŠ” λ„€νŠΈμ›Œν¬μ— μ ‘μ†ν•˜κΈ° μœ„ν•œ κ΅¬μ‘°μ²΄μž…λ‹ˆλ‹€.

/* sockaddr_in6 ꡬ쑰체 */
struct sockaddr_in6 {
	sa_family_t sin6_family; // = 항상 AF_INET6
	in_port_t sin6_port;
	uint32_t sin6_flowinfo;
	struct in6_addr sin6_addr;
	uint32_t sin6_scope_id;
};

struct in6_addr {
	unsigned char s6_addr[16];
};
  • sin6_family: sockaddr의 sa_family와 κ°™μŠ΅λ‹ˆλ‹€.
  • sin6_port: 톡신을 μœ„ν•΄ μ‚¬μš©ν•  포트 λ²ˆν˜Έμž…λ‹ˆλ‹€.
  • sin6_flowinfo: λΌμš°ν„°κ°€ νŒ¨ν‚·μ΄ μ „λ‹¬λ˜λŠ” 경둜λ₯Ό κ²°μ •ν•˜λŠ”λ° ν•„μš”ν•œ κ°’μž…λ‹ˆλ‹€.
  • sin6_addr: 접속할 λŒ€μƒ(μƒλŒ€λ°©)의 IP μ£Όμ†Œμž…λ‹ˆλ‹€.
  • sin6_scope_id: 버전에 따라 이 λ©€λ²„λŠ” 없을 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. IP μ£Όμ†Œμ— λ”°λ₯Έ 계측이 μ μ ˆν•œμ§€λ₯Ό κ²€μ¦ν•©λ‹ˆλ‹€. 계측은 μ•„λž˜ κ°’ 쀑 ν•˜λ‚˜μž…λ‹ˆλ‹€.
    • 0x0: reserved, 0x1: interface-local, 0x2: link-local, 0x4: admin-local, 0x5: site-local, 0x8: organization-local, 0xe: global, 0xf: reserved

2.4 sockaddr_un ꡬ쑰체

μ„œλ‘œ λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€(싀행쀑인 ν”„λ‘œκ·Έλž¨) 사이에 데이터λ₯Ό μ£Όκ³ λ°›μ•„μ•Ό ν•  λ•Œ μ‚¬μš©λ˜λŠ” κ΅¬μ‘°μ²΄μž…λ‹ˆλ‹€.

/* sockaddr_un ꡬ쑰체 */
struct sockaddr_un {
	sa_family_t sun_family;
	char sun_path[UNIX_PATH_MAX];
};
  • sun_family: sockaddr ꡬ쑰체의 sa_family와 κ°™μŠ΅λ‹ˆλ‹€.
  • sun_path: μ†ŒμΌ“μœΌλ‘œ 접속할 파일의 κ²½λ‘œμž…λ‹ˆλ‹€. UNIX_PATH_MAXλŠ” μƒμˆ˜ 108μž…λ‹ˆλ‹€.

λ‹€μ–‘ν•œ ꡬ쑰체λ₯Ό μ•Œμ•„λ³΄μ•˜μœΌλ‹ˆ, 이 쀑 κ°€μž₯ 보편적으둜 μ‚¬μš©λ˜λŠ” IPv4 톡신인 sockaddr_in κ΅¬μ‘°μ²΄λ₯Ό μ‚¬μš©ν•΄ μΈν„°λ„·λ§μ— μ—°κ²°ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. 

3. μ†ŒμΌ“ 톡신 ν”„λ‘œκ·Έλž˜λ° (ν΄λΌμ΄μ–ΈνŠΈ): TCP ν”„λ‘œν† μ½œ

https://recipes4dev.tistory.com/153

  • ν΄λΌμ΄μ–ΈνŠΈ: 접속 λŒ€μƒμ˜ sockaddr_in ꡬ쑰체 μ„ΈνŒ… - socket() ν•¨μˆ˜ - connect() ν•¨μˆ˜μ˜ 3λ‹¨κ³„λ‘œ 접속이 μ§„ν–‰λ˜λ©°,
  • μ„œλ²„: μžμ‹ μ˜ sockaddr_in ꡬ쑰체 μ„ΈνŒ… - socket() ν•¨μˆ˜ - bind() ν•¨μˆ˜ - listen() ν•¨μˆ˜ - accept() ν•¨μˆ˜μ˜ 5λ‹¨κ³„λ‘œ 접속이 μ§„ν–‰λ©λ‹ˆλ‹€.

3.1 sockaddr_in ꡬ쑰체 μ„€μ •ν•˜κΈ°

접속할 λ„€νŠΈμ›Œν¬, 접속 λŒ€μƒκ³Ό 포트 번호λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.

/* sock_ex01.c */
struct sockaddr_in sock;

/* μ£Όμ†Œ μ²΄κ³„λ‘œμ„œ IPv4λ₯Ό μ‚¬μš©ν•˜λŠ” 인터넷망에 접속 */
sock.sin_family = AF_INET;
/* 접속할 λŒ€μƒμ€ 127.0.0.1 */
sock.sin_addr.s_addr = inet_addr("127.0.0.1");
/* 포트 λ²ˆν˜ΈλŠ” 1435 */
sock.sin_port = htons(1435);

htons, htonl, htonll, htonf, htond와 ntohs, ntohl, ntohll, ntohf, ntohdλŠ” λ°”μ΄νŠΈ λ³€ν™˜ ν•¨μˆ˜μž…λ‹ˆλ‹€. htonκ³Ό ntohλŠ” 각각 Host to Network, Network to Host의 μ•½μžλ‘œ HostλŠ” 접속 단말기, NetworkλŠ” λ„€νŠΈμ›Œν¬λ₯Ό 톡해 μ „λ‹¬λ˜λŠ” 경둜λ₯Ό λœ»ν•©λ‹ˆλ‹€. Intel CPUλ₯Ό μ‚¬μš©ν•˜λŠ” 개인용 μ»΄ν“¨ν„°λŠ” Little Endian을 μ‚¬μš©ν•˜κ³ , 일뢀 CPUλŠ” Big Endian 방식을 μ‚¬μš©ν•˜μ§€λ§Œ, λ„€νŠΈμ›Œν¬λŠ” 항상 Big Endian으둜 데이터가 μ „λ‹¬λ˜κΈ° λ•Œλ¬Έμ— 이λ₯Ό λ³€ν™˜ν•  ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€. htonκ³Ό ntoh 뒀에 λΆ™λŠ” s, l, ll, f, dλŠ” μ „μ†‘λ˜λŠ” λ°μ΄ν„°μ˜ μžλ£Œν˜•μ„ λœ»ν•©λ‹ˆλ‹€.

  • htons / ntohs : unsigned short ν˜•μ˜ Endian을 λ³€ν™˜ν•©λ‹ˆλ‹€.
  • htonl / ntohl : unsigned long ν˜•μ˜ Endian을 λ³€ν™˜ν•©λ‹ˆλ‹€.
  • htonll / ntohll : unslgned long ν˜•μ˜ Endian을 λ³€ν™˜ν•©λ‹ˆλ‹€.
  • htonf / ntohf : float ν˜•μ˜ Endian을 λ³€ν™˜ν•©λ‹ˆλ‹€.
  • htond / ntohd : double ν˜•μ˜ Endian을 λ³€ν™˜ν•©λ‹ˆλ‹€.

3.2 socket μƒμ„±ν•˜κΈ°

IPv4λ₯Ό μ‚¬μš©ν•˜λŠ” 인터넷망에 μ ‘μ†ν•˜κΈ° μœ„ν•œ μ†ŒμΌ“μ„ λ§Œλ“€μ–΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

/* μ‚¬μš© 예 */
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
/* μ†ŒμΌ“ λ§Œλ“€κΈ°μ— μ‹€νŒ¨ μ‹œ INVALID_SOCKET이 λ°˜ν™˜ */
if(sock == INVALID_SOCKET) printf("Invalid Socket");

이 쀑 socket() ν•¨μˆ˜λŠ” 데이터 κ΅ν™˜μ„ μœ„ν•œ μ†ŒμΌ“μ„ μƒμ„±ν•©λ‹ˆλ‹€. κΈ°λ³Έ 골격은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

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

af: μ ‘μ†ν•˜λŠ” 방식을 μ§€μ •ν•©λ‹ˆλ‹€.

  1. AF_UNSPEC: 기타 λ„€νŠΈμ›Œν¬μ— μ ‘μ†ν•©λ‹ˆλ‹€.
  2. AF_INET: IPv4 μ£Όμ†Œμ²΄κ³„λ₯Ό μ‚¬μš©ν•˜λŠ” 인터넷 망에 μ ‘μ†ν•©λ‹ˆλ‹€.
  3. AF_IPX: IPX/SPX μ£Όμ†Œμ²΄κ³„λ₯Ό μ‚¬μš©ν•˜λŠ” λ„€νŠΈμ›Œν¬μ— μ ‘μ†ν•©λ‹ˆλ‹€. Windows 운영체제의 경우 Windows Vista μ΄ν›„λ‘œ μ§€μ›ν•˜μ§€ μ•ŠλŠ” λͺ¨λ“œμž…λ‹ˆλ‹€.
  4. AF_APPLETALK: AppleTalk λ„€νŠΈμ›Œν¬μ— μ ‘μ†ν•©λ‹ˆλ‹€. Windows 운영체제의 경우 Windows Vista μ΄ν›„λ‘œ μ§€μ›ν•˜μ§€ μ•ŠλŠ” λͺ¨λ“œμž…λ‹ˆλ‹€.
  5. AF_NETBIOS: NetBIOS λ„€νŠΈμ›Œν¬μ— μ ‘μ†ν•©λ‹ˆλ‹€. Windows 운영체제의 경우 32λΉ„νŠΈ λ²„μ „μ—μ„œλ§Œ 이 λͺ¨λ“œκ°€ μ§€μ›λ©λ‹ˆλ‹€.
  6. AF_INET6: IPv6 μ£Όμ†Œμ²΄κ³„λ₯Ό μ‚¬μš©ν•˜λŠ” 인터넷망에 μ ‘μ†ν•©λ‹ˆλ‹€.
  7. AF_IRDA: 적외선 톡신(IrDA)으둜 μƒλŒ€νŽΈμ—κ²Œ μ ‘μ†ν•©λ‹ˆλ‹€.
  8. AF_BTH: λΈ”λ£¨νˆ¬μŠ€λ‘œ μƒλŒ€νŽΈμ—κ²Œ μ ‘μ†ν•©λ‹ˆλ‹€.

type: 데이터λ₯Ό κ΅ν™˜ν•˜λŠ” 방식을 μ§€μ •ν•©λ‹ˆλ‹€. 일반적으둜 TCP ν”„λ‘œν† μ½œλ‘œ 톡신할 λ•Œ SOCK_STREAM, UDP ν”„λ‘œν† μ½œλ‘œ 톡신할 λ•Œ SOCK_DGRAM을 μ‚¬μš©ν•˜κ³ , κ°€κ³΅ν•˜μ§€ μ•Šμ€ λ°©μ‹μœΌλ‘œ 직접 νŒ¨ν‚·μ„ μˆ˜μ‹ ν•˜κ±°λ‚˜ νŒ¨ν‚·μ„ λ§Œλ“€μ–΄ 톡신할 λ•Œ SOCK_RAWλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

  1. SOCK_STREAM: μž…/좜λ ₯ μž‘λ™μ˜ 슀트림 λ°©μ‹μœΌλ‘œ 데이터λ₯Ό κ΅ν™˜ν•©λ‹ˆλ‹€. AF_INET, AF_INET6μ—μ„œ 일반적으둜 μ‚¬μš©ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.
  2. SOCK_DGRAM: λ°μ΄ν„°κ·Έλž¨μ˜ ν˜•νƒœλ‘œ 데이터λ₯Ό κ΅ν™˜ν•©λ‹ˆλ‹€. AF_INET, AF_INET6μ—μ„œλŠ” UDP ν”„λ‘œν† μ½œμ„ μ‚¬μš©ν•  λ•Œ 이 방식이 μ§€μ •λ˜λ©°, NetBIOS도 이 λ°©μ‹μœΌλ‘œ 지정해야 ν•©λ‹ˆλ‹€.
  3. SOCK_RAW: μ €μˆ˜μ€€μœΌλ‘œ 데이터λ₯Ό κ΅ν™˜ν•˜κ³ μž ν•  λ•Œ μ§€μ •λ©λ‹ˆλ‹€. IPv4 헀더λ₯Ό μˆ˜μ •ν•˜κ³  μ‹Άλ‹€λ©΄ IP_HDRINCL, IPv6 헀더λ₯Ό μˆ˜μ •ν•˜κ³  μ‹Άλ‹€λ©΄ IPV6_HDRINCL μ˜΅μ…˜μ΄ ν•¨κ»˜ μ§€μ •λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.
  4. SOCK_RDM: λ©€ν‹°μΊμŠ€νŠΈ(ν•œ μ„œλ²„μ—μ„œ λΌμš°ν„°μ— μ—°κ²°λœ λͺ¨λ“  μ»΄ν“¨ν„°λ‘œ μΌκ΄„μ μœΌλ‘œ 데이터λ₯Ό 전솑)λ₯Ό μ‚¬μš©ν•˜κ³  싢을 λ•Œ μ§€μ •ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.
  5. SOCK_SEQPACKET: λͺ¨λ¦„

protocol: μ‚¬μš©ν•  ν”„λ‘œν† μ½œμ„ μ§€μ •ν•©λ‹ˆλ‹€. IPPROTO_ICMP, IPPROTO_IGMP, BTHPROTO_RFCOMM, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_ICMPV6, IPPROTO_RM λ“±μ˜ μ–΄λ €μš΄ 방식듀이 μ—΄κ±°λ˜λŠ”λ° AF_INETμ—μ„œλŠ” κ·Έλƒ₯ μƒμˆ˜ 0만 넣어도 λ©λ‹ˆλ‹€.

3.3 μƒμ„±ν•œ socket으둜 μƒλŒ€νŽΈμ—κ²Œ 접속

socket() ν•¨μˆ˜λ‘œ 인터넷망에 μ ‘μ†ν•˜κΈ° μœ„ν•œ μ†ŒμΌ“μ„ μƒμ„±ν–ˆκ³  sockaddr_in ꡬ쑰체둜 접속할 λŒ€μƒμ„ μ§€μ •ν•˜μ˜€μŠ΅λ‹ˆλ‹€. μƒλŒ€λ°©μ—κ²Œ μ ‘μ†ν•˜κΈ° μœ„ν•œ ν•¨μˆ˜λŠ” connectμž…λ‹ˆλ‹€.

int connect(SOCKET s, const struct sockaddr * name, int namelen);
  • s: 접속에 ν•„μš”ν•œ μ†ŒμΌ“μž…λ‹ˆλ‹€.
  • name: μ†ŒμΌ“μœΌλ‘œ 접속할 λŒ€μƒμž…λ‹ˆλ‹€.
  • namelen: name의 ν¬κΈ°μž…λ‹ˆλ‹€. sizeof μ—°μ‚°μžλ‘œ sockaddr_in ꡬ쑰체의 크기λ₯Ό μž…λ ₯ν•˜λ©΄ λ©λ‹ˆλ‹€.

연결에 μ„±κ³΅ν•˜λ©΄ 0을 λ°˜ν™˜ν•˜μ§€λ§Œ, μ‹€νŒ¨ μ‹œ SOCKET_ERROR μƒμˆ˜λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

3.4 κ°„λ‹¨ν•œ 예제 μ½”λ“œ

/* μ‚¬μš© 예 */
struct sockaddr_in sockaddr_internet;
SOCKET sock;
int connection;

/* -------- 1 단계 -------- */
/* μ£Όμ†Œ μ²΄κ³„λ‘œμ„œ IPv4λ₯Ό μ‚¬μš©ν•˜λŠ” 인터넷망에 접속 */
sockaddr_internet.sin_family = AF_INET;
/* 접속할 λŒ€μƒμ€ 127.0.0.1 */
sockaddr_internet.sin_addr.s_addr = inet_addr("127.0.0.1");
/* 포트 λ²ˆν˜ΈλŠ” 1435 */
sockaddr_internet.sin_port = htons(1435);

/* -------- 2 단계 -------- */
/* 슀트림 λ°©μ‹μœΌλ‘œ 인터넷 망에 μ ‘μ†ν•˜κΈ° μœ„ν•œ μ†ŒμΌ“μ„ 생성 */
sock = socket(AF_INET, SOCK_STREAM, 0);
/* μ†ŒμΌ“ λ§Œλ“€κΈ°μ— μ‹€νŒ¨ μ‹œ INVALID_SOCKET이 λ°˜ν™˜ */
if(sock == INVALID_SOCKET) printf("Invalid Socket");

/* -------- 3 단계 -------- */
connection = connect(sock, sockaddr_internet, sizeof(struct sockaddr_in));
if(connection == SOCKET_ERROR) printf("Socket Error");

4. μ†ŒμΌ“ 톡신 ν”„λ‘œκ·Έλž˜λ° (μ„œλ²„): TCP ν”„λ‘œν† μ½œ

μ΄λ²ˆμ—λŠ” μ„œλ²„κ°€ λ˜μ–΄ 접속 μš”μ²­μ„ λ°›μ•„λ“€μ—¬λ³΄κ² μŠ΅λ‹ˆλ‹€.

4.1 sockaddr_in ꡬ쑰체 μ„€μ •ν•˜κΈ°

sockaddr_in ꡬ쑰체 섀정은 ν΄λΌμ΄μ–ΈνŠΈμ™€ 크게 λ‹€λ₯΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ‹€λ§Œ μžμ‹ μ˜ IP μ£Όμ†Œλ₯Ό λͺ…μ‹œν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 차이가 μžˆμŠ΅λ‹ˆλ‹€.

/* μ‚¬μš© 예 */
struct sockaddr_in sockaddr_internet;
 
/* μ£Όμ†Œ μ²΄κ³„λ‘œμ„œ IPv4λ₯Ό μ‚¬μš©ν•˜λŠ” 인터넷망에 접속 */
sockaddr_internet.sin_family = AF_INET;
/* 접속할 λŒ€μƒμ„ μ§€μ •ν•˜μ§€ μ•ŠμŒ */
serveraddr.sin_addr.s_addr = inet_addr(INADDR_ANY);
/* 포트 λ²ˆν˜ΈλŠ” 1435 */
serveraddr.sin_port = htons(1435);
  • INADDR_ANY: μžλ™μœΌλ‘œ 이 컴퓨터에 μ‘΄μž¬ν•˜λŠ” λžœμΉ΄λ“œ 쀑 μ‚¬μš©κ°€λŠ₯ν•œ λžœμΉ΄λ“œμ˜ IPμ£Όμ†Œλ₯Ό μ‚¬μš©ν•˜λΌλŠ” μ˜λ―Έμž…λ‹ˆλ‹€. μ„œλ²„ μ†ŒμΌ“μ„ 생성할 λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.

4.2 socket μƒμ„±ν•˜κΈ°

λ„€νŠΈμ›Œν¬μ— μ ‘μ†ν•˜κΈ° μœ„ν•œ μ†ŒμΌ“μ„ μƒμ„±ν•©λ‹ˆλ‹€. 이 μ—­μ‹œ ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ μƒμ„±ν•œ 방식과 κ°™μŠ΅λ‹ˆλ‹€.

/* μ‚¬μš© 예: 인터넷에 μ ‘μ†ν•˜μ—¬ 슀트림 λ°©μ‹μœΌλ‘œ μž…μΆœλ ₯ν•˜λŠ” μ†ŒμΌ“ 생성 */
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
/* μ†ŒμΌ“ λ§Œλ“€κΈ°μ— μ‹€νŒ¨ μ‹œ INVALID_SOCKET이 λ°˜ν™˜ */
if(sock == INVALID_SOCKET) printf("Invalid Socket");

4.3 μƒμ„±ν•œ μ†ŒμΌ“μ„ 접속을 λ°›λŠ” μš©λ„λ‘œ 지정

bind ν•¨μˆ˜λŠ” μƒμ„±λœ μ†ŒμΌ“μ— 지역 IP μ£Όμ†Œμ™€ 포트 번호λ₯Ό μ—°κ²°μ‹œμΌœ μ„œλ²„μš© μ†ŒμΌ“μœΌλ‘œ λ§Œλ“€μ–΄μ£ΌλŠ” 역할을 ν•©λ‹ˆλ‹€.

int bind(SOCKET s, const struct sockaddr * name, int namelen);
  • s: μ„œλ²„μš©μœΌλ‘œ μ‚¬μš©ν•  μ†ŒμΌ“μž…λ‹ˆλ‹€.
  • name: 자기 μžμ‹ μ˜ sockaddr κ΅¬μ‘°μ²΄μž…λ‹ˆλ‹€.
  • namelen: μ—¬κΈ°μ—μ„œλŠ” sockaddr_in ꡬ쑰체의 ν¬κΈ°μž…λ‹ˆλ‹€.
/* μ‚¬μš© 예 */
int state;
state = bind(sock , (struct sockaddr *)&sockaddr_internet, sizeof(sockaddr_in));
if (state == SOCKET_ERROR) printf("Socket Error");

4.4 접속이 λ“€μ–΄μ˜¬λ•ŒκΉŒμ§€ λŒ€κΈ°

μ„œλ²„λ‘œμ„œ κ°–μΆ”μ–΄μ•Ό ν•  μ€€λΉ„λŠ” λͺ¨λ‘ λλ‚¬μŠ΅λ‹ˆλ‹€. 이제 μ†λ‹˜μ΄ 접속할 λ•ŒκΉŒμ§€ 계속 κΈ°λ‹€λ¦¬κΈ°λ§Œ ν•˜λ©΄ λ©λ‹ˆλ‹€. 이 역할을 ν•˜λŠ” ν•¨μˆ˜λŠ” listen() ν•¨μˆ˜μž…λ‹ˆλ‹€.

int listen(SOCKET s, int backlog);
  • s: μ„œλ²„μš©μœΌλ‘œ μ“°λŠ” μ†ŒμΌ“μž…λ‹ˆλ‹€.
  • backlog: μ΅œλŒ€ λŒ€κΈ°μž μˆ˜μ— ν•΄λ‹Ήν•˜λŠ” μ •μˆ˜ κ°’μž…λ‹ˆλ‹€. 이 κ°’μ˜ 기쀀은 λ”°λ‘œ 정해지지 μ•Šμ•˜κ³  κ²½ν—˜μ μœΌλ‘œ 5 정도면 μ λ‹Ήν•˜λ‹€κ³  μ•Œλ €μ Έ μžˆμŠ΅λ‹ˆλ‹€.
/* μ‚¬μš© 예: μ ‘μ†μžκ°€ λ“€μ–΄μ˜¬λ•ŒκΉŒμ§€ λ‚΄λΆ€μ μœΌλ‘œ λ¬΄ν•œλ£¨ν”„λ₯Ό 돌리며 계속 이 λ‹¨κ³„μ—μ„œ 머물게 될 κ²ƒμž…λ‹ˆλ‹€.
int state = listen(sock, 5);
/* listen도 였λ₯˜μ‹œ SOCKET_ERRORλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. μ ‘μ†μž 1λͺ…을 μ„±κ³΅μ μœΌλ‘œ λ°›μ•„λ“€μ˜€λ‹€λ©΄ 0이 λ°˜ν™˜λ  κ²ƒμž…λ‹ˆλ‹€. */
if(state == SOCKET_ERROR) printf("Socket Error");

4.5 μžμ‹ μ—κ²Œ μ ‘μ†ν•œ μœ μ €μ˜ sockaddr_in μ–»κΈ°

μ„œλ²„λ‘œ 열어두고 접속을 κΈ°λ‹€λ ΈμœΌλ©΄ μžμ‹ μ—κ²Œ λ“€μ–΄μ˜¨ μœ μ €κ°€ λˆ„κ΅¬μΈμ§€λ₯Ό μ•Œ ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€. ν΄λΌμ΄μ–ΈνŠΈκ°€ connect ν•¨μˆ˜λ‘œ μžμ‹ μ—κ²Œ μ ‘μ†ν•˜λ©΄μ„œ ν΄λΌμ΄μ–ΈνŠΈ μžμ‹ μ˜ sockaddr_in ꡬ쑰체의 λ‚΄μš©λ„ μ„œλ²„μ—κ²Œ μ „ν•΄μ§€λŠ”λ° 이 역할은 accept ν•¨μˆ˜μ—μ„œ μˆ˜ν–‰ν•©λ‹ˆλ‹€.

SOCKET accept(SOCKET s, struct sockaddr * addr, int * addrlen);
  • s: μ„œλ²„μš©μœΌλ‘œ μ“°κ³  μžˆλŠ” μ†ŒμΌ“μž…λ‹ˆλ‹€.
  • addr: 접속 μœ μ €μ— λŒ€ν•œ 정보λ₯Ό μ €μž₯ν•  sockaddr ꡬ쑰체 ν¬μΈν„°μž…λ‹ˆλ‹€.
  • addrlen: μ ‘μ†λœ μœ μ €μ— λŒ€ν•œ 정보가 λͺ‡ λ°”μ΄νŠΈμΈμ§€λ„ 이 λ³€μˆ˜λ₯Ό 톡해 얻을 수 μžˆμŠ΅λ‹ˆλ‹€.

λ°˜ν™˜ κ°’μœΌλ‘œ μ ‘μ†μž 1인에 λŒ€ν•œ μ†ŒμΌ“μ΄ λ°˜ν™˜λ©λ‹ˆλ‹€.

/* μ‚¬μš© 예 */
SOCKET sockClient;
struct sockaddr_in sockaddrClient;
int sockaddrSize = 0;
sockClient = accept(sock, (struct sockaddr *)&sockaddrClient, &sockaddrSize);
if(sockClient == INVALID_SOCKET) printf("Invalid Socket");
else printf("μ ‘μ†μž IPλŠ” %s이고 ꡬ쑰체 ν¬κΈ°λŠ” %dλ°”μ΄νŠΈμž…λ‹ˆλ‹€.", inet_ntoa(sockaddrClient.sin_addr), sockaddrSize);

5. 데이터 κ΅ν™˜: TCP ν”„λ‘œν† μ½œ

5.1 데이터 κ΅ν™˜: send(), recv()

이제 μ„œλ²„μ™€ ν΄λΌμ΄μ–ΈνŠΈκ°„μ˜ μ—°κ²° μž‘μ—…μ€ λͺ¨λ‘ λ§ˆμ³€μŠ΅λ‹ˆλ‹€. 이제 본격적으둜 데이터λ₯Ό κ΅ν™˜ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. λ°μ΄ν„°μ˜ κ΅ν™˜μ€ 전솑을 λ‹΄λ‹Ήν•˜λŠ” send와 μˆ˜μ‹ μ„ λ‹΄λ‹Ήν•˜λŠ” recv ν•¨μˆ˜λ‘œ μˆ˜ν–‰λ©λ‹ˆλ‹€.

int send(SOCKET s, const char * buf, int len, int flags);
int recv(SOCKET s, char * buf, int len, int flags);
  • s: 데이터λ₯Ό μ£Όκ³  받을 λŒ€μƒμ„ λ‚˜νƒ€λ‚΄λŠ” μ†ŒμΌ“μž…λ‹ˆλ‹€.
  • buf: μ£Όκ³  받을 데이터가 κΈ°λ‘λ˜μ–΄μžˆκ±°λ‚˜ 기둝될 λ²„νΌμž…λ‹ˆλ‹€.
  • len: λ²„νΌμ˜ 크기(λ°”μ΄νŠΈ)μž…λ‹ˆλ‹€.
  • flags: μ†‘μˆ˜μ‹  κ΄€λ ¨ μ˜΅μ…˜μž…λ‹ˆλ‹€. ν˜„μž¬λ‘œμ„œλŠ” 0으둜 해도 λ¬΄λ°©ν•©λ‹ˆλ‹€.

5.2 데이터 κ΅ν™˜ 예제: send(), recv()

λ°μ΄ν„°μ˜ κ΅ν™˜μ€ μ„œλ²„μ™€ ν΄λΌμ΄μ–ΈνŠΈκ°„μ˜ μ—°κ²° μž‘μ—…μ„ 마친 ν›„ 전솑을 λ‹΄λ‹Ήν•˜λŠ” send와 μˆ˜μ‹ μ„ λ‹΄λ‹Ήν•˜λŠ” recv ν•¨μˆ˜λ‘œ μˆ˜ν–‰λ©λ‹ˆλ‹€. λ°˜ν™˜ 값은 μƒλŒ€λ°©μ—κ²Œ μ‹€μ œλ‘œ 솑신 λ˜λŠ” μˆ˜μ‹ ν•œ 데이터 λ°”μ΄νŠΈ 수둜 len보닀 μž‘κ±°λ‚˜ 같을 수 μžˆμŠ΅λ‹ˆλ‹€. 전솑 이상 μ‹œ SOCKET_ERROR이 λ°˜ν™˜λ©λ‹ˆλ‹€.

/* μ‚¬μš© 예 */
/* μƒλŒ€λ°©μœΌλ‘œ 보낼 λ©”μ‹œμ§€ */
char message[] = "Hello, World!";
/* μƒλŒ€λ°©μ—κ²Œμ„œ μ „ν•΄μ˜€λŠ” λ©”μ‹œμ§€ */
char buffer[256];

// ... μ†ŒμΌ“ μ„ΈνŒ… μƒλž΅

strcpy(buffer, message);

/* 보낼 λ•Œ */
printf("sending...\n");
status = send(sockServer, buffer, sizeof(buffer), 0);
if (status == SOCKET_ERROR) // 전솑 이상 μ‹œ μ†ŒμΌ“ λ‹«κ³  ν”„λ‘œκ·Έλž¨ μ’…λ£Œ
{
	printf("send Error.\n");
	closesocket(sockServer);
	return -1;
}
printf("sent.\n");

/* 받을 λ•Œ */
printf("receiving...\n");
status = recv(sockServer, buffer, sizeof(buffer), 0);
if (status == SOCKET_ERROR)
{
	printf("recv Error.\n");
	closesocket(sockServer);
	return -1;
}
printf("received.\n");

5.3 send/recv 와 write/readν•¨μˆ˜μ˜ 차이?

send/recv 와 write/readν•¨μˆ˜λŠ” 거의 μœ μ‚¬ν•˜μ§€λ§Œ, 일뢀 차이가 μžˆμŠ΅λ‹ˆλ‹€.

UNIX/Linuxμ—μ„œ λͺ¨λ“  μž₯치/μžμ›μ€ FILE이기에 μ†ŒμΌ“μ΄λž€ μžμ›λ„ read/writeλΌλŠ” μΈν„°νŽ˜μ΄μŠ€λ‘œ μž…μΆœλ ₯을 μˆ˜ν–‰ν•©λ‹ˆλ‹€(recv/send도 μ‚¬μš©κ°€λŠ₯). ν•˜μ§€λ§Œ Windowsμ—μ„œλŠ” μ†ŒμΌ“μ΄ FILE둜 κ΄€λ¦¬λ˜μ§€ μ•ŠκΈ°μ— recv/send만 μ‚¬μš©κ°€λŠ₯ν•©λ‹ˆλ‹€. μΆ”κ°€λ‘œ recv/sendλŠ” μ†ŒμΌ“ μ „μš© μΈν„°νŽ˜μ΄μŠ€μ΄κΈ°μ— 뒀에 μΆ”κ°€ μ˜΅μ…˜μ΄ 더 넣을 수 μžˆμŠ΅λ‹ˆλ‹€.

read/write: the universal file descriptor functions working on all

  • ssize_t read(int fd, void *buf, size_t count); (엔터값도 μ €μž₯함.)
  • ssize_t write(int fd, const void *buf, size_t count);

recv/send: work only on socket descriptors (socket μ „μš©)

  • ssize_t recv(int s, void *buf, size_t len, int flags);
  • ssize_t send(int s, const void *buf, size_t len, int flags);

read()/write() is equivalent to recv()/send() with a flags parameter of 0(flags == 0)

6. μ†ŒμΌ“ 톡신 ν”„λ‘œκ·Έλž˜λ° (ν΄λΌμ΄μ–ΈνŠΈ, μ„œλ²„): UDP ν”„λ‘œν† μ½œ

μ΄λ²ˆμ—λŠ” μœ„μ™€ 같이 μ†ŒμΌ“ν”„λ‘œκ·Έλž˜λ°μ„ ν•˜λ˜ UDP ν”„λ‘œν† μ½œμΌ 경우, λ°”κΏ”μ•Ό ν•˜λŠ” ꡬ성에 λŒ€ν•΄ μ„€λͺ…ν•˜λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€. μœ„μ™€ 거의 λ™μΌν•˜λ©° μΌλΆ€λ§Œ λ³€κ²½λœλ‹€λŠ” 점을 κΈ°μ–΅ν•΄λ‘μ‹œλ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€.

6.1 μ†ŒμΌ“ 생성

ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„ μ†ŒμΌ“μ„ 생성할 λ•Œ, SOCK_STREAM으둜 μƒμ„±ν•˜λ˜ κΈ°μ‘΄κ³Ό 달리 SOCK_DGRAM 으둜 μƒμ„±ν•©λ‹ˆλ‹€. 

SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);

6.2 μ†ŒμΌ“μ˜ 자료 μ†‘μˆ˜μ‹ 

UDP/IP ν†΅μ‹ μ—μ„œλŠ” TCP/IPμ™€λŠ” 달리 read()와 write()λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  recvform()κ³Ό sendto()ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ 자료λ₯Ό μ†‘μˆ˜μ‹ ν•©λ‹ˆλ‹€. sendto()ν•¨μˆ˜λ₯Ό λŒ€μ‹  μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” 전솑할 λͺ©μ μ§€λ₯Ό 지정할 수 있기 λ•Œλ¬Έμ΄λ©°, recvform()ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” μˆ˜μ‹ λ˜λŠ” 자료 외에도 μ†‘μ‹ μ§€μ˜ 정보λ₯Ό ν•¨κ»˜ 얻을 수 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ TCP/IP처럼 ν•œλ²ˆ μ—°κ²°λ˜λ©΄ μ—°κ²°λœ μ‹œμŠ€ν…œκ³Ό 자료λ₯Ό μ£Όκ³  λ°›μ§€λ§Œ UDP/IPλŠ” 자유둭게 μ‹œμŠ€ν…œ μ£Όμ†Œλ₯Ό λ°”κΎΈμ–΄ κ°€λ©΄μ„œ 자료λ₯Ό μ†‘μˆ˜μ‹  ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

6.2.1 자료 솑신: sendto()

int sendto(SOCKET s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
  • SOCKET s: μ†ŒμΌ“ λ””μŠ€ν¬λ¦½ν„°
  • void *msg: 전솑할 데이터
  • size_t len: λ°μ΄ν„°μ˜ λ°”μ΄νŠΈ λ‹¨μœ„ 길이
  • int flags: 전솑을 μœ„ν•œ μ˜΅μ…˜
  • sockaddr *to: λͺ©μ μ§€ μ£Όμ†Œ 정보
  • socklen_t tolen: λͺ©μ μ§€ μ£Όμ†Œ μ •λ³΄μ˜ 크기

6.2.2 sendto() 예제

uint32_t send_data;
struct sockaddr_in* local_addr_p = &local_addr;

if( (sock_fd != -1) && local_addr_p)
{
	const char *sendMsg = "shuffle";
	send_data = sendto(sock_fd, sendMsg, strlen(sendMsg), 0, (struct sockaddr*)local_addr_p, sizeof(local_addr));
	if(send_mbr != strlen(sendMsg))
	{
		printf("sendto failure : ret(%u) slen(%d)\n", send_data, strlen(sendMsg) + 1);
	}
}

6.2.3 자료 μˆ˜μ‹ : recvform()

μ„œλ²„μš© μ†ŒμΌ“μœΌλ‘œ μƒμ„±ν•˜κΈ° μœ„ν•œ bind ν›„ 데이터λ₯Ό λ°›κΈ° μœ„ν•΄ λŒ€κΈ°ν•˜λŠ” 방식이 λ‹€λ¦…λ‹ˆλ‹€. TCP의 경우 listen으둜 λŒ€κΈ°ν•˜λ©΄ λ˜μ§€λ§Œ, UDP의 경우 recvfrom ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ μ²˜λ¦¬ν•΄μ•Ό ν•©λ‹ˆλ‹€.
int recvfrom(SOCKET s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)​
  • SOCKET s: μ†ŒμΌ“ λ””μŠ€ν¬λ¦½ν„°
  • void *buf: 자료 μˆ˜μ‹ μ„ μœ„ν•œ 버퍼 포인터
  • size_t len: λ²„νΌμ˜ λ°”μ΄νŠΈ λ‹¨μœ„ 길이
  • int flags: μˆ˜μ‹ μ„ μœ„ν•œ μ˜΅μ…˜
  • sockaddr *from: μ „μ†‘ν•œ 곳의 μ£Όμ†Œ 정보
  • socklen_t fromlen: μ „μ†‘ν•œ μ£Όμ†Œ μ •λ³΄μ˜ 크기 

6.2.4 recvform() 예제

state = bind(sock, (struct sockaddr*)&sockaddr_internet, sizeof(sockaddr_in));
while(1)
{
    int clntLen = sizeof(clntAddr);
    int recvLen = recvfrom(sock, recvBuf, BUFSIZE, 0, (struct sockaddr*)&clntAddr, (socklen_t *)&clntLen)
    if(recvLen == -1)
    {
        printf("recvfrom failed\n");
        break;
    }
    else if (recvLen > 0)
    {
        ... 
        μˆ˜μ‹  데이터 처리
        ...
    }
}

 

μ°Έκ³ 

λ°˜μ‘ν˜•