TCPIP Source

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 228

1.1.

1 서버 프로그램

< 소스 hello_server.c>

#include <stdio.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define PORT 9000

char buffer[BUFSIZ] = "hello, world";

main( )

int c_socket, s_socket;

struct sockaddr_in s_addr, c_addr;

int len;

int n;

s_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(PORT);

if(bind(s_socket, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

1
return -1;

if(listen(s_socket, 5) == -1) {

printf("listen Fail\n");

return -1;

while(1) {

len = sizeof(c_addr);

c_socket = accept(s_socket, (struct sockaddr *) &c_addr, &len);

n = strlen(buffer);

write(c_socket, buffer, n);

close(c_socket);

close(s_socket);

</ 소스 >

1.1.2 클라이언트 프로그램

< 소스 hello_client.c>

#include <stdio.h>

#include <netinet/in.h>

#include <sys/socket.h>

2
#define PORT 9000

#define IPADDR "127.0.0.1"

main( )

int c_socket;

struct sockaddr_in c_addr;

int len;

int n;

char rcvBuffer[BUFSIZ];

c_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&c_addr, 0, sizeof(c_addr));

c_addr.sin_addr.s_addr = inet_addr(IPADDR);

c_addr.sin_family = AF_INET;

c_addr.sin_port = htons(PORT);

if(connect(c_socket, (struct sockaddr *) &c_addr, sizeof(c_addr))==-1) {

printf("Can not connect\n");

close(c_socket);

return -1;

if((n = read(c_socket, rcvBuffer, sizeof(rcvBuffer))) < 0) {

3
return (-1);

rcvBuffer[n] = '\0';

printf("received Data : %s\n", rcvBuffer);

close(c_socket);

</ 소스 >

1.2 텔넷으로 웹 서버에 접속하기

1.3.1 클라이언트 프로그램

< 소스 HelloClientDlg.h>

// HelloClientDlg.h : 헤더 파일

#pragma once

#include "afxwin.h"

// CHelloClientDlg 대화 상자

class CHelloClientDlg : public CDialog

// 생성입니다 .

public:

CHelloClientDlg(CWnd* pParent = NULL);// 표준 생성자입니다 .

// 대화 상자 데이터입니다 .

4
enum { IDD = IDD_HELLOCLIENT_DIALOG };

protected:

virtual void DoDataExchange(CDataExchange* pDX);// DDX/DDV 지원입니다 .

// 구현입니다 .

protected:

HICON m_hIcon;

// 생성된 메시지 맵 함수

virtual BOOL OnInitDialog( );

afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

afx_msg void OnPaint( );

afx_msg HCURSOR OnQueryDragIcon( );

DECLARE_MESSAGE_MAP( )

public:

CStatic m_static_status; --①

public:

afx_msg void OnBnClickedButtonConnect( ); --②

};

</ 소스 >

< 소스 HelloClientDlg.cpp>

// HelloClientDlg.cpp : 구현 파일

//

#include "stdafx.h"

5
#include "HelloClient.h"

#include "HelloClientDlg.h"

void CHelloClientDlg::OnBnClickedButtonConnect( )--①

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다 .

// HelloServer 에 연결하기 위해 소켓 오브젝트 생성하여 연결

CSocket socket;

socket.Create( );

socket.Connect(_T("127.0.0.1"), 9000);

//서버에 연결하면 서버가 바로보내는 문자열 ("Hello, World") 수신

int cbRcvd;

char buffer[1024];

CStringstr Buffer = _T("");

if((cbRcvd = socket.Receive(buffer, 1024)) > 0) {

//strBuffer = (LPCSTR)(LPSTR)buffer;

strBuffer.Format("%s", buffer);

m_static_status.SetWindowText(strBuffer.Left(cbRcvd));

socket.Close( );

</ 소스 >

1.3.2 서버 프로그램

6
< 소스 ListenSocket.h>

#pragma once

// CListenSocket 명령 대상입니다 .

class CHelloServerDlg; --①

class CListenSocket : public CSocket

public:

CListenSocket(CHelloServerDlg* pHelloServerDlg); --②

virtual ~CListenSocket( );

CHelloServerDlg* m_pHelloServerDlg; --③

public:

virtual void OnAccept(int nErrorCode); --④

};

</ 소스 >

< 소스 ListenSocket.cpp>

// ListenSocket.cpp : 구현 파일입니다 .

//

#include "stdafx.h"

#include "HelloServer.h"

#include "ListenSocket.h"

#include "HelloServerDlg.h" --①

7
// CListenSocket

CListenSocket::CListenSocket(CHelloServerDlg* pHelloServerDlg) --②

m_pHelloServerDlg = pHelloServerDlg; --③

CListenSocket::~CListenSocket( )

// CListenSocket 멤버 함수

void CListenSocket::OnAccept(int nErrorCode)

// TODO: 여기에 특수화된 코드를 추가 및 / 또는 기본 클래스를 호출합니다 .

m_pHelloServerDlg->ProcessAccept( ); --④

CSocket::OnAccept(nErrorCode);

</ 소스 >

< 소스 ServiceSocket.h>

#pragma once

// CServiceSocket 명령 대상입니다 .

8
class CHelloServerDlg; --①

class CServiceSocket : public CSocket

public:

CServiceSocket(CHelloServerDlg* pHelloServerDlg); --②

virtual ~CServiceSocket( );

CHelloServerDlg* m_pHelloServerDlg; --③

};

</ 소스 >

< 소스 ServiceSocket.cpp>

// ServiceSocket.cpp : 구현 파일입니다 .

#include "stdafx.h"

#include "HelloServer.h"

#include "ServiceSocket.h"

#include "HelloServerDlg.h" --①

// CServiceSocket

CServiceSocket::CServiceSocket(CHelloServerDlg* pHelloServerDlg) --②

m_pHelloServerDlg = pHelloServerDlg; --③

CServiceSocket::~CServiceSocket( )

9
{

</ 소스 >

< 소스 HelloServerDlg.h>

// HelloServerDlg.h : 헤더 파일

#pragma once

#include "afxwin.h"

#include "ListenSocket.h" --①

#include "ServiceSocket.h" --+

// CHelloServerDlg 대화 상자

class CHelloServerDlg : public CDialog

// 생성입니다 .

public:

CHelloServerDlg(CWnd* pParent = NULL);// 표준 생성자입니다 .

// 대화 상자 데이터입니다 .

enum { IDD = IDD_HELLOSERVER_DIALOG };

protected:

virtual void DoDataExchange(CDataExchange* pDX);// DDX/DDV 지원입니다 .

// 구현입니다 .

protected:

HICON m_hIcon;

10
// 생성된 메시지 맵 함수

virtual BOOL OnInitDialog( );

afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

afx_msg void OnPaint( );

afx_msg HCURSOR OnQueryDragIcon( );

DECLARE_MESSAGE_MAP( )

public:

CListenSocket* m_pListenSocket; --②

CServiceSocket* m_pServiceSocket; --+

public:

CButton m_button_start; --③

CStatic m_static_status; --+

public:

void ProcessAccept(void); --④

public:

afx_msg void OnBnClickedButtonStart( ); --⑤

};

</ 소스 >

< 소스 HelloServerDlg.cpp>

// HelloServerDlg.cpp : 구현 파일

#include "stdafx.h"

#include "HelloServer.h"

#include "HelloServerDlg.h"

11
void CHelloServerDlg::OnBnClickedButtonStart( ) --①

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다 .

UINT nPort = 9000;

m_pListenSocket = new CListenSocket(this);

m_static_status.SetWindowText(_T("Create Listen SOcket"));

if(!m_pListenSocket->Create(nPort)) {

m_static_status.SetWindowText(_T("Cannot Create Socket"));

return;

} else {

m_static_status.SetWindowText(_T("Socket Create Success"));

if(!m_pListenSocket->Listen( )) {

m_static_status.SetWindowText(_T("can not listen"));

return;

void CHelloServerDlg::ProcessAccept(void) --②

m_pServiceSocket = new CServiceSocket(this);

char sndBuffer[ ] = "Hello, World";

if(m_pListenSocket->Accept(*m_pServiceSocket)) {

m_static_status.SetWindowText(_T("Accepted"));

12
m_pServiceSocket->Send(sndBuffer, (int)strlen(sndBuffer));

m_static_status.SetWindowText(_T("Send Hello,World"));

} else {

delete m_pServiceSocket;

</ 소스 >

13
2 장 내친김에 소켓 프로그래밍 확장하기

2.1 hello, world 를 출력하는 소켓 프로그램의 기능 확장

2.1.1 서버 프로그램

< 소스 hello_ext_server.c>

#include <stdio.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define PORT 9000

char buffer[BUFSIZ] = "hello, world";

char rBuffer[BUFSIZ];

main( )

int c_socket, s_socket;

struct sockaddr_in s_addr, c_addr;

int len;

int n, i;

16

char *temp;

int length;

19

s_socket = socket(PF_INET, SOCK_STREAM, 0);

14
21

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(PORT);

26

if(bind(s_socket, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

31

if(listen(s_socket, 5) == -1) {

printf("listen Fail\n");

return -1;

36

while(1) {

len = sizeof(c_addr);

c_socket = accept(s_socket, (struct sockaddr *) &c_addr, &len);

length = 0;

temp = rBuffer;

while((n = read(c_socket, temp, 1)) > 0) {

if(*temp == '\r') continue;

if(*temp == '\n') break;

15
if(*temp == '\0') break;

if(length == BUFSIZ) break;

temp++; length++;

rBuffer[length] = '\0';

if(!strcmp(rBuffer, "print") ) {

n = strlen(buffer);

write(c_socket, buffer, n);

close(c_socket);

close(s_socket);

</ 소스 >

2.1.2 클라이언트 프로그램

< 소스 hello_ext_client.c>

#include <stdio.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <strings.h>

#define PORT 9000

16
#define IPADDR "127.0.0.1"

char buffer[BUFSIZ];

main( )

int c_socket;

struct sockaddr_in c_addr;

int len;

char rcvBuffer[BUFSIZ];

int n;

c_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&c_addr, 0, sizeof(c_addr));

c_addr.sin_addr.s_addr = inet_addr(IPADDR);

c_addr.sin_family = AF_INET;

c_addr.sin_port = htons(PORT);

27

if(connect(c_socket, (struct sockaddr *) &c_addr, sizeof(c_addr)) == -1) {

printf("Can not connect\n");

close(c_socket);

return -1;

17
scanf("%s", buffer);

buffer[strlen(buffer)] = '\0';

write(c_socket, buffer, strlen(buffer)+1);

if((n = read(c_socket, rcvBuffer, sizeof(rcvBuffer))) < 0) {

return (-1);

rcvBuffer[n] = '\0';

printf("received Data : %s\n", rcvBuffer);

44

close(c_socket);

</ 소스 >

2.2 파일 목록을 출력하는 소켓 프로그램의 구현

2.2.1 파일 목록 읽어 내기

< 소스 list.c>

#include <dirent.h>

#include <stdio.h>

main( )

DIR *dp;

18
struct dirent *dir;

if((dp = opendir(".")) == NULL) {

fprintf(stderr, "directory open error\n");

exit(-1);

while((dir = readdir(dp)) != NULL) {

if(dir->d_ino == 0) continue;

printf("%s\n", dir->d_name);

closedir(dp);

</ 소스 >

2.2.2 서버 프로그램

< 소스 ls_server.c>

//ls_server.c

#include <stdio.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <dirent.h>

#define PORT 9000

19
char err_1[ ]="Directory Error";

char rBuffer[BUFSIZ];

main( )

int c_socket, s_socket;

struct sockaddr_in s_addr, c_addr;

int len, length;

int n, i;

char *temp;

DIR *dp;

struct dirent *dir;

s_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(PORT);

if(bind(s_socket, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

20
if(listen(s_socket, 5) == -1) {

printf("listen Fail\n");

return -1;

while(1) {

len = sizeof(c_addr);

c_socket = accept(s_socket, (struct sockaddr *) &c_addr, &len);

length = 0;

temp = rBuffer;

while((n = read(c_socket, temp, 1)) > 0) {

if(*temp == '\r') continue;

if(*temp == '\n') break;

if(*temp == '\0') break;

if(length == BUFSIZ) break;

temp++; length++;

rBuffer[length] = '\0';

if(!strcmp(rBuffer, "ls") ) {

if((dp = opendir(".")) == NULL) {

21
write(c_socket, err_1, strlen(err_1));

} else {

while((dir = readdir(dp)) != NULL) {

if(dir->d_ino == 0) continue;

write(c_socket, dir->d_name, strlen(dir->d_name));

write(c_socket, " ", 1);

closedir(dp);

close(c_socket);

close(s_socket);

</ 소스 >

2.2.3 클라이언트 프로그램

< 소스 ls_client.c>

//ls_client.c

#include <stdio.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <strings.h>

#define PORT 9000

22
#define IPADDR "127.0.0.1"

char buffer[BUFSIZ];

main( )

int c_socket;

struct sockaddr_in c_addr;

int len;

char rcvBuffer[BUFSIZ];

19

char *temp;

int length = 0;

int n;

24

c_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&c_addr, 0, sizeof(c_addr) );

c_addr.sin_addr.s_addr = inet_addr(IPADDR);

c_addr.sin_family = AF_INET;

c_addr.sin_port = htons(PORT);

if(connect(c_socket, (struct sockaddr *) &c_addr, sizeof(c_addr)) == -1) {

printf("Can not connect\n");

23
close(c_socket);

return -1;

scanf("%s", buffer);

buffer[strlen(buffer)] = '\0';

if((n = write(c_socket, buffer, strlen(buffer)+1)) < 0) {

printf("write error\n");

exit(-1);

temp = rcvBuffer;

while((n = read(c_socket, temp, 1)) > 0) {

if(length == BUFSIZ) break;

temp++; length++;

rcvBuffer[length] = '\0';

52

printf("received Data : %s\n", rcvBuffer);

close(c_socket);

</ 소스 >

24
3 장 소켓 프로그래밍에서 알아야 할 기본

3.3 소켓의 생성과 종료

< 소스 sock_open.c>

//sock_open.c

#include <stdio.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

main( )

int tcpSd1, tcpSd2;

int udpSd1, udpSd2;

if((tcpSd1 = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {

perror("socket( )-tcpSd1");

} else

printf("TCP socket open = %d\n", tcpSd1);

if((udpSd1 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {

perror("socket( )-udpSd1");

} else

printf("UDP socket open = %d\n", udpSd1);

if((tcpSd2 = socket(PF_INET, SOCK_STREAM, IPPROTO_UDP)) < 0) {

25
perror("socket( )-tcpSd2");

} else

printf("TCP socket open = %d\n", tcpSd2);

if((udpSd2 = socket(PF_INET, SOCK_DGRAM, IPPROTO_TCP)) < 0) {

perror("socket( )-udpSd2");

} else

printf("UDP socket open = %d\n", udpSd2);

close(tcpSd1);

close(udpSd1);

close(tcpSd2);

close(udpSd2);

</ 소스 >

< 소스 file_sock_open.c>

//file_sock_open.c

#include <stdio.h>

#include <sys/types.h>

#include <fcntl.h>

#include <sys/socket.h>

main( )

int fd;

int sd;

26
fd = open("/etc/services", O_RDONLY);

sd = socket(PF_INET, SOCK_STREAM, 0);

printf("fd = [%d] \n", fd);

printf("sd = [%d] \n", sd);

</ 소스 >

< 소스 stdio.c>

//stdio.c

#include <stdio.h>

#include <sys/socket.h>

main( ) {

int sd;

char str[100];

sd = socket(PF_INET, SOCK_STREAM, 0);

fscanf(stdin, "%s", str);

fprintf(stdout, "%s \n", str);

fprintf(stderr, "sd = [%d] \n", sd);

</ 소스 >

< 소스 sockpair.c>

27
//sockpair.c

#include <stdio.h>

#include <sys/socket.h>

main( )

int sd[2], result;

int n1, n2;

char buf[BUFSIZ];

char data[ ] = "This is from sd[0]";

result = socketpair(PF_LOCAL, SOCK_STREAM, 0, sd);

n1 = write(sd[0], data, strlen(data));

printf("[send] %s\n", data);

n2 = read(sd[1], buf, BUFSIZ);

buf[n2] = '\0';

printf("[received] %s\n", buf);

close(sd[0]);

close(sd[1]);

</ 소스 >

3.6 socketpair 함수를 이용한 소켓 프로그램의 구현 – 두 프로세스 간에

28
< 소스 sockpair_fork.c>

//sockpair_fork.c

#include <stdio.h>

#include <sys/socket.h>

char data1[ ] = "From Parent";

char data2[ ] = "From Child";

main( ) {

int pid;

int sd[2], result;

char buf[BUFSIZ];

result = socketpair(PF_LOCAL, SOCK_STREAM, 0, sd);

pid = fork( );

if(pid > 0) { // 부모 프로세스

close(sd[1]);

read(sd[0], buf, BUFSIZ);

printf("[parent:%d] %s\n", getpid( ), buf);

write(sd[0], data1, sizeof(data1));

close(sd[0]);

} else if(pid == 0) { // 자식 프로세스

close(sd[0]);

29
write(sd[1], data2, sizeof(data2));

read(sd[1], buf, BUFSIZ);

printf("[child:%d] %s\n", getpid( ), buf);

close(sd[1]);

} else if(pid == -1) {

perror("fork( )");

</ 소스 >

30
PART 2 단일 접속 서버 구현하기

4 장 클라이언트 / 서버 모델

4.1 포트 (Port) 와 서비스 (Service)

4.1.2 포트별 서비스 내역을 출력하는 프로그램

< 소스 getservent.c>

//getservent.c

#include <stdio.h>

#include <netdb.h>

int

main( ) {

struct servent *p;

int n;

while(1) {

if(!(p = getservent( ))) break;

printf("%s\t %d/%s \t", p->s_name, ntohs(p->s_port), p->s_proto);

for(n = 0; p->s_aliases[n] != NULL; n++)

printf("%s ", p->s_aliases[n]);

printf("\n");

31
</ 소스 >

4.2.1 바이트 순서 (Byte Order)

< 소스 ordering.c>

//ordering.c

#include <stdio.h>

main( )

short data;

char *ch;

data = 0x1234;

ch = (char *) &data;

printf("original data : 0x1234\n" );

if(ch[0] == 0x12 && ch[1] == 0x34 )

printf("host data(big-endian) : ");

else if(ch[1] == 0x12 && ch[0] == 0x34 )

printf("host data(little-endian) : ");

printf("0x%x%x\n", ch[0], ch[1]);

</ 소스 >

32
4.2.2 네트워크 / 호스트 바이트 순서 간 자료 변환

< 소스 ntoh_hton.c>

//ntoh_hton.c

#include <stdio.h>

main( ) {

short hostData = 0x1234;

short netData;

char *ch;

printf("original data : 0x1234\n" );

ch = (char *) &hostData;

if(ch[0] == 0x12 && ch[1] == 0x34)

printf("host(big-endian) : ");

else if(ch[1] == 0x12 && ch[0] == 0x34)

printf("host(little-endian) : ");

printf("0x%x%x\n", ch[0], ch[1]);

netData = htons(hostData);

ch = (char *) &netData;

printf("network data(big-endian) : 0x%x%x\n", ch[0], ch[1]);

33
</ 소스 >

4.2.3 IP 주소 변환

< 소스 inet_aton.c>

//inet_aton.c

#include <stdio.h>

#include <arpa/inet.h>

main( ) {

struct in_addr inp;

const char *ipAddr ="203.249.39.3";

char *addr;

inet_aton(ipAddr, &inp);

printf("ip(dotted decimal)[%s] -> ip(binary)[0x%x]\n", ipAddr, ntohl(inp.s_addr));

addr = inet_ntoa(inp);

printf("ip(binary)[0x%x] -> ip(dotted decimal)[%s]\n", ntohl(inp.s_addr), addr);

</ 소스 >

< 소스 gethostbyname.c>

//gethostbyname.c

#include <netdb.h>

#include <sys/socket.h>

34
main( ) {

struct in_addr addr;

struct hostent *host;

const char *hostName = "www.yahoo.com";

int i;

10

if((host = gethostbyname(hostName)) == NULL) {

printf("gethostbyname( ) error - check network\n");

exit(-1);

printf("official name = %s\n", host->h_name);

17

i = 0;

while(host->h_aliases[i] != NULL ) {

printf("aliases = %s\n", host->h_aliases[i++]);

22

printf("address type = %d\n", host->h_addrtype);

printf("address length = %d\n", host->h_length);

25

i = 0;

while(host->h_addr_list[i] != NULL) {

memcpy(&addr.s_addr, host->h_addr_list[i], 4);

printf("address = %s(0x%x)\n", inet_ntoa(addr), ntohl(*(long *)host-

35
>h_addr_list[i]));

i++;

</ 소스 >

4.2.4 프로토콜 주소의 구성

< 소스 remote_addr.c>

//remote_addr.c

#include <stdio.h>

#include <sys/socket.h>

#include <netinet/in.h>

main( )

int tcpSd;

struct sockaddr_in s_addr;

if((tcpSd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {

perror("socket( )");

exit(-1);

bzero((char *) &s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

36
inet_aton("203.249.39.3", &s_addr.sin_addr.s_addr);

s_addr.sin_port = htons(7);

printf("ip(dotted decial) = %s\n", inet_ntoa(s_addr.sin_addr.s_addr));

printf("ip(binary) = %x\n", ntohl(s_addr.sin_addr.s_addr));

printf("port no = %d\n", ntohs(s_addr.sin_port));

close(tcpSd);

</ 소스 >

37
5장 TCP 소켓 프로그래밍

5.1 서버 프로그램의 기능 수행

5.1.1 연결 준비 단계

< 소스 bind_listen.c>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

main( )

int s_socket;

struct sockaddr_in s_addr;

s_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = inet_addr("203.249.39.141"); // 자신의 IP 주소로 변경

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(0);

if(bind(s_socket, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

38
return -1;

listen(s_socket, 0);

while(1) {

sleep(2);

close(s_socket);

</ 소스 >

5.3 TCP 기반 에코 (Echo) 프로그램의 구현

5.3.1 서버 프로그램

< 소스 echo_server.c>

//echo_server.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define PORT 9000

main( )

39
{

int c_socket, s_socket;

struct sockaddr_in s_addr, c_addr;

int len;

int n;

char rcvBuffer[BUFSIZ];

s_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(PORT);

if(bind(s_socket, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

if(listen(s_socket, 5) == -1) {

printf("listen Fail\n");

return -1;

while(1) {

40
len = sizeof(c_addr);

c_socket = accept(s_socket, (struct sockaddr *) &c_addr, &len);

while((n = read(c_socket, rcvBuffer, sizeof(rcvBuffer))) != 0) {

rcvBuffer[n] = '\0';

printf("%s", rcvBuffer);

write(c_socket, rcvBuffer, n);

close(c_socket);

close(s_socket);

</ 소스 >

5.3.2 클라이언트 프로그램

< 소스 echo_client.c>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define PORT 9000

#define IPADDR "127.0.0.1"

41
main( )

int c_socket;

struct sockaddr_in c_addr;

int len;

char sndBuffer[BUFSIZ], rcvBuffer[BUFSIZ];

int n;

int n_left, n_recv;

c_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&c_addr, 0, sizeof(c_addr));

c_addr.sin_addr.s_addr = inet_addr(IPADDR);

c_addr.sin_family = AF_INET;

c_addr.sin_port = htons(PORT);

if(connect(c_socket, (struct sockaddr *) &c_addr, sizeof(c_addr)) == -1) {

printf("Can not connect\n");

close(c_socket);

return -1;

while(1) {

if((n = read(0, sndBuffer, BUFSIZ)) > 0) {

42
sndBuffer[n] = '\0';

if(!strcmp(sndBuffer, "quit\n")) break;

printf("original Data : %s", sndBuffer);

if((n = write(c_socket, sndBuffer, strlen(sndBuffer))) < 0) {

return (-1);

n_left = n;

n_recv = 0;

while(n_left > 0) {

if((n=read(c_socket, &rcvBuffer[n_recv], n_left)) < 0) {

return (-1);

n_left = n_left - n;

n_recv = n_recv + n;

rcvBuffer[n_recv] = '\0';

printf("echoed Data : %s", rcvBuffer);

close(c_socket);

43
< 소스 >

44
6장 UDP 소켓 프로그래밍

6.3 UDP 기반 에코 프로그램의 구현

6.3.1 서버 프로그램

< 소스 echo_server_UDP.c>

//echo_server_UDP.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

main(int argc, char *argv[ ])

int sd;

struct sockaddr_in s_addr, c_addr;

char buff[BUFSIZ];

int n, n_recv;

int addr_len;

sd = socket(AF_INET, SOCK_DGRAM, 0);

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_port = htons(9200);

45
if(bind(sd, (struct sockaddr *) &s_addr, sizeof(s_addr)) < 0){

fprintf(stderr, "bind( ) error");

exit(-2);

while(1) {

28

fprintf(stderr, "waiting\n");

30

addr_len = sizeof(c_addr);

if((n_recv = recvfrom(sd, buff, sizeof(buff), 0, (struct sockaddr *)&c_addr,

&addr_len)) < 0) {

fprintf(stderr, "recvfrom( ) error");

exit(-3);

if((n = sendto(sd, buff, n_recv, 0, (struct sockaddr *) &c_addr, sizeof(c_addr))) <

0){

fprintf(stderr, "sendto( ) error");

exit(-3);

close(sd);

</ 소스 >

46
6.3.2 클라이언트 프로그램

< 소스 echo_client_UDP.c>

//echo_client_UDP.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

main(int argc, char *argv[ ])

int sd;

struct sockaddr_in s_addr;

char sndBuffer[BUFSIZ];

int n, n_send;

int addr_len;

sd = socket(AF_INET, SOCK_DGRAM, 0);

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

s_addr.sin_port = htons(9200);

while(1) {

47
fprintf(stderr, "waiting\n");

25

if((n = read(0, sndBuffer, BUFSIZ)) > 0) {

sndBuffer[n] = '\0';

if(!strcmp(sndBuffer, "quit\n")) break;

printf("original Data : %s", sndBuffer);

if ((n_send = sendto(sd, sndBuffer, strlen(sndBuffer), 0, (struct sockaddr *)

&s_addr, sizeof(s_addr))) < 0){

fprintf(stderr, "sendto( ) error");

exit(-3);

addr_len = sizeof(s_addr);

if((n = recvfrom(sd, sndBuffer, sizeof(sndBuffer), 0, NULL, NULL)) < 0) {

fprintf(stderr, "recvfrom( ) error");

exit(-3);

sndBuffer[n] = '\0';

printf("echoed Data : %s", sndBuffer);

close(sd);

48
}

</ 소스 >

6.4 UDP에서의 신뢰성 문제

6.4.1 자료 전송 중의 손실

< 소스 echo_client_UDPalarm.c>

//echo_client_UDPalarm.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <signal.h>

#include <errno.h>

void sigAlarm(int);

main(int argc, char *argv[ ])

int sd;

struct sockaddr_in s_addr;

char sndBuffer[BUFSIZ];

int n, n_send;

int addr_len;

int status;

struct sigaction act;

49
act.sa_handler = sigAlarm;

sigemptyset(&act.sa_mask);

act.sa_flags = 0;

status = sigaction(SIGALRM, &act, 0);

sd = socket(AF_INET, SOCK_DGRAM, 0);

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

s_addr.sin_port = htons(9200);

while(1) {

fprintf(stderr, "waiting\n");

if((n = read(0, sndBuffer, BUFSIZ)) > 0) {

sndBuffer[n] = '\0';

if(!strcmp(sndBuffer, "quit\n")) break;

printf("original Data : %s", sndBuffer);

if((n_send = sendto(sd, sndBuffer, strlen(sndBuffer), 0, (struct sockaddr *)

&s_addr, sizeof(s_addr))) < 0){

50
fprintf(stderr, "sendto( ) error");

exit(-3);

alarm(2);

addr_len = sizeof(s_addr);

fprintf(stderr, "socket recvfrom enter\n");

if((n = recvfrom(sd, sndBuffer, sizeof(sndBuffer), 0, NULL, NULL)) < 0) {

if(errno == EINTR)

fprintf(stderr, "socket timeout\n");

else

fprintf(stderr, "recvfrom error\n");

} else {

alarm(0);

sndBuffer[n] = '\0';

printf("echoed Data : %s", sndBuffer);

close(sd);

void

sigAlarm(int signo)

51
fprintf(stderr, "alarm\n");

return;

</ 소스 >

6.4.2 응답 대상에 대한 확인

< 소스 echo_client_UDPconfirm.c>

//echo_client_UDPconfirm.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

//#include <string.h>

main(int argc, char *argv[ ])

int sd;

struct sockaddr_in s_addr, c_addr;

char sndBuffer[BUFSIZ];

int n, n_send;

int addr_len;

sd = socket(AF_INET, SOCK_DGRAM, 0);

17

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

52
s_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

s_addr.sin_port = htons(9200);

while(1) {

fprintf(stderr, "waiting\n");

if((n = read(0, sndBuffer, BUFSIZ)) > 0) {

28

sndBuffer[n] = '\0';

if(!strcmp(sndBuffer, "quit\n")) break;

printf("original Data : %s", sndBuffer);

if((n_send = sendto(sd, sndBuffer, strlen(sndBuffer), 0, (struct sockaddr *)

&s_addr, sizeof(s_addr))) < 0){

fprintf(stderr, "sendto( ) error");

exit(-3);

38

addr_len = sizeof(c_addr);

if((n = recvfrom(sd, sndBuffer, sizeof(sndBuffer), 0, (struct sockaddr

*)&c_addr, &addr_len)) < 0) {

fprintf(stderr, "recvfrom( ) error");

exit(-3);

53
44

if(memcmp(&c_addr, &s_addr, addr_len) != 0) {

fprintf(stderr, "reply from %s/%d (ignored)\n",

inet_ntoa(c_addr.sin_addr.s_addr), ntohs(c_addr.sin_port));

continue;

sndBuffer[n] = '\0';

50

printf("echoed Data : %s", sndBuffer);

close(sd);

</ 소스 >

6.4.3 서버의 미실행 오류

< 소스 echo_client_UDPconnect.c>

//echo_client_UDPconnect.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

main(int argc, char *argv[ ])

int sd;

54
struct sockaddr_in s_addr;

char sndBuffer[BUFSIZ];

int n, n_send;

int addr_len;

sd = socket(AF_INET, SOCK_DGRAM, 0);

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

s_addr.sin_port = htons(9000);

connect(sd, (struct sockaddr *) &s_addr, sizeof(s_addr));

while(1) {

fprintf(stderr, "waiting\n");

27

if((n = read(0, sndBuffer, BUFSIZ)) > 0 ) {

sndBuffer[n] = '\0';

if(!strcmp(sndBuffer, "quit\n")) break;

printf("original Data : %s", sndBuffer);

if((n_send = write(sd, sndBuffer, strlen(sndBuffer))) < 0){

55
fprintf(stderr, "write error");

exit(-3);

addr_len = sizeof(s_addr);

if((n = read(sd, sndBuffer, sizeof(sndBuffer))) < 0) {

fprintf(stderr, "read error");

exit(-3);

sndBuffer[n] = '\0';

printf("echoed Data : %s", sndBuffer);

close(sd);

</ 소스 >

6.5 UDP를 이용한 브로드캐스팅 (Broadcasting)

< 소스 UDPbcaster.c>

//UDPbcaster.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

56
#include <netinet/in.h>

#include <signal.h>

#include <errno.h>

main(int argc, char* argv[ ])

int sd;

struct sockaddr_in s_addr;

char sndBuffer[BUFSIZ];

int n, n_send, status;

int on = 1;

if(argc != 3) {

fprintf(stderr, "usage: UDPbacster broadcast_ip_addr port\n");

exit(-1);

sd = socket(AF_INET, SOCK_DGRAM, 0);

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_addr.s_addr = inet_addr(argv[1]);

s_addr.sin_port = htons(atoi(argv[2]));

if((status = setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on))) != 0) {

printf("setsockopt error\n");

57
exit(-1);

while(1) {

fprintf(stderr, "Type broadcasting data : ");

if((n = read(0, sndBuffer, BUFSIZ)) > 0) {

sndBuffer[n-1] = '\0';

if((n_send = sendto(sd, sndBuffer, strlen(sndBuffer), 0, (struct sockaddr

*)&s_addr, sizeof(s_addr))) < 0){

fprintf(stderr, "sendto() error");

exit(-3);

if (!strncmp(sndBuffer, "quit", 4)) break;

close(sd);

</ 소스 >

< 소스 UDPreader.c>

//echo_client_UDPbcast.c

58
#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <errno.h>

main(int argc, char* argv[ ])

int sd;

struct sockaddr_in s_addr, c_addr;

char rcvBuffer[BUFSIZ];

int n, n_send;

int addr_len;

int status;

int on = 1;

if(argc != 2) {

printf("usage: UDPreader port\n");

exit(-1);

sd = socket(AF_INET, SOCK_DGRAM, 0);

bzero(&s_addr, sizeof(s_addr));

59
s_addr.sin_family = AF_INET;

s_addr.sin_addr.s_addr = INADDR_ANY;

s_addr.sin_port = htons(atoi(argv[1]));

if(bind(sd, (struct sockaddr *)&s_addr, sizeof(s_addr)) != 0) {

fprintf(stderr, "bind error\n");

exit(-2);

while(1) {

addr_len = sizeof(s_addr);

if((n = recvfrom(sd, rcvBuffer, sizeof(rcvBuffer), 0, (struct sockaddr *)&c_addr,

&addr_len)) < 0) {

fprintf(stderr, "recvfrom error");

exit(-3);

rcvBuffer[n] = '\0';

if(!strncmp(rcvBuffer, "quit", 4))

break;

printf("Broadcated from %s [%s]\n", inet_ntoa(c_addr.sin_addr.s_addr),

rcvBuffer);

close(sd);

60
</ 소스 >

61
PART 3 다중 접속 서버 구현하기

7 장 멀티프로세싱 방식의 다중 접속 서버

7.2 fork 함수

< 소스 fork_test.c>

//fork_test.c

#include <stdio.h>

main( )

int pid;

int a = 10;

int b = 20;

a = a + 1;

pid = fork( );

if(pid > 0) {

a = a + 1;

printf("PARENT");

} else if(pid == 0) {

b = b + 1;

printf("CHILD");

printf("[%d] a=%d/b=%d\n", getpid( ), a, b);

62
}

</ 소스 >

7.3 fork 함수를 이용한 다중 접속 서버의 구현

< 소스 echo_server_fork.c>

//echo_server_fork.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define PORT 8090

void do_echo(int);

main( )

int connSock, listenSock;

struct sockaddr_in s_addr, c_addr;

int len;

pid_t pid;

listenSock = socket(PF_INET, SOCK_STREAM, 0);

63
memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(PORT);

if(bind(listenSock, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

if(listen(listenSock, 5) == -1) {

printf("listen Fail\n");

return -1;

while(1) {

len = sizeof(c_addr);

connSock = accept(listenSock, (struct sockaddr *) &c_addr, &len);

if((pid = fork( )) < 0) {

printf("echo server can not fork( )\n");

return -1;

} else if(pid > 0) {

close(connSock);

continue;

64
} else if(pid == 0 ) {

close(listenSock);

do_echo(connSock);

void

do_echo(int connSock) {

int n;

char rcvBuffer[BUFSIZ];

while((n = read(connSock, rcvBuffer, sizeof(rcvBuffer))) != 0) {

printf("child\n");

write(connSock, rcvBuffer, n);

exit(0);

</ 소스 >

7.4 시그널 (Signal) 과 좀비 (Zombie) 프로세스

7.4.1 시그널의 등록과 처리

< 소스 sigact.c>

#include <stdio.h>

#include <signal.h>

65
struct sigaction act_new;

struct sigaction act_old;

void

sig_handler(int signo)

printf( "First Ctrl-C pressed !! \n");

11

sigaction(SIGINT, &act_old, NULL);

int main(void)

act_new.sa_handler = sig_handler;

sigemptyset(&act_new. sa_mask);

act_new.sa_flags = 0;

sigaction(SIGINT, &act_new, &act_old);

while(1)

printf("sigaction test \n");

sleep(1);

</ 소스 >

66
7.4.2 wait 함수로 자식 프로세스의 종료 상태 확인

< 소스 wait_sigchld.c>

#include <stdio.h>

#include <stdlib.h>

#include <signal.h>

#include <sys/wait.h>

void do_child(void);

void do_parent(void);

void

sighandler(int n)

int stat, chld_pid;

sigset_t newset, oldset;

chld_pid = wait(&stat);

printf("signal ID [%d]\n", n);

17

if(WIFEXITED(stat)) {

printf("normal termination, exit status [%d]\n", WEXITSTATUS(stat));

} else if(WIFSIGNALED(stat)) {

printf("abnormal termination, signal number [%d]\n", WTERMSIG(stat));

} else if(WIFSTOPPED(stat)) {

printf("child stopped, signal number [%d]\n", WSTOPSIG(stat));

67
}

26

exit(1);

int

main( )

int pid;

struct sigaction sigset, oldset;

sigset.sa_handler = sighandler;

sigset.sa_flags = 0;

sigemptyset(&sigset.sa_mask);

sigaction(SIGCHLD, &sigset, &oldset);

if((pid = fork( )) == 0) {

do_child( );

} else if(pid > 0) {

do_parent( );

void

do_child( )

exit(100);

68
}

void do_parent( )

sleep(10);

</ 소스 >

7.4.3 좀비 프로세스의 생성 방지

< 소스 echo_server_fork_sig.c>

//echo_server_fork_sig.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <signal.h>

#include <sys/wait.h>

#define PORT 8090

void do_echo(int);

void sigHandler(int);

main( )

69
int connSock, listenSock;

struct sockaddr_in s_addr, c_addr;

int len;

pid_t pid;

int state;

struct sigaction act;

act.sa_handler = sigHandler;

sigemptyset(&act.sa_mask);

act.sa_flags=0;

state=sigaction(SIGCHLD, &act, 0);

if(state != 0) {

printf("signal error\n");

exit(1);

listenSock = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(PORT);

70
if(bind(listenSock, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

if(listen(listenSock, 5) == -1) {

printf("listen Fail\n");

return -1;

while(1) {

len = sizeof(c_addr);

if((connSock=accept(listenSock, (struct sockaddr *) &c_addr, &len))<0) {

printf("accept error\n");

if((pid = fork( )) < 0) {

printf("echo server can not fork( )\n");

return -1;

} else if(pid > 0) {

close(connSock);

continue;

} else if(pid == 0 ) {

printf("child creat\n");

close(listenSock);

71
do_echo(connSock);

void

do_echo(int connSock)

int n;

char rcvBuffer[BUFSIZ];

81

while((n = read(connSock, rcvBuffer, sizeof(rcvBuffer))) != 0) {

printf("child(%d)\n", n);

write(connSock, rcvBuffer, n);

exit(1);

void

sigHandler(int sig)

int pid;

int status;

pid = wait(&status);

printf("pid[%d] terminate\n", pid);

72
}

</ 소스 >

7.5.1 서버 프로그램

< 소스 talk_server.c>

//talk_server.c

// $ talk_server port#

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <signal.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

void do_keyboard(int);

void do_socket(int);

char quit[ ] = "exit";

pid_t pid;

int

main(int argc, char *argv[ ]) {

int listenSock, connSock;

struct sockaddr_in client_addr, server_addr;

73
int len;

if(argc < 2) {

printf("Usage: talkServer port_num ");

return -1;

if((listenSock=socket(PF_INET, SOCK_STREAM, 0)) < 0) {

printf("Server: Can't open socket\n");

return -1;

bzero((char *) &server_addr, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

server_addr.sin_port = htons(atoi(argv[1]));

40

if(bind(listenSock, (struct sockaddr *) &server_addr, sizeof(server_addr))<0) {

printf("talk Server Can't bind \n");

return -1;

listen(listenSock, 1);

len = sizeof(client_addr);

74
if((connSock=accept(listenSock,(struct sockaddr *) &client_addr, &len))<0) {

printf("Talk Server failed in accepting\n");

return -1;

printf("Talk Server accept new request\n");

if((pid = fork( )) < 0) {

printf("fork error\n");

return -1;

} else if(pid > 0) {

do_keyboard(connSock);

} else if(pid == 0) {

do_socket(connSock);

close(listenSock);

close(connSock);

void

do_keyboard(int connSock)

int n;

char sbuf[BUFSIZ];

while((n = read(0, sbuf, BUFSIZ)) > 0) {

75
if(write(connSock, sbuf, n) != n) {

printf("Talk Server fail in sending\n");

if(strncmp(sbuf, quit, 4) == 0) {

kill(pid, SIGQUIT);

break;

void

do_socket(int connSock)

int n;

char rbuf[BUFSIZ];

while(1) {

if((n = read(connSock, rbuf, BUFSIZ)) > 0) {

rbuf[n] = '\0';

printf("%s", rbuf);

if(strncmp(rbuf, quit, 4) == 0) {

kill(getppid( ), SIGQUIT);

break;

76
}

</ 소스 >

7.5.2 클라이언트 프로그램

< 소스 talk_client.c>

//talk_client.c

// - talkClient IP_address port_number

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <signal.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

void do_keyboard(int);

void do_socket(int);

char quit[ ] = "exit";

pid_t pid;

int

main(int argc, char *argv[ ]) {

77
int connSock;

struct sockaddr_in server_addr;

char *serverAddr;

int serverPort;

int len;

if(argc != 3) {

printf("Usage: talk_client server_ip port_num ");

return -1;

} else {

serverAddr = argv[1];

serverPort = atoi(argv[2]);

if((connSock=socket(PF_INET, SOCK_STREAM, 0)) < 0) {

printf("Talk Client Can't open socket\n");

return -1;

bzero((char *) &server_addr, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = inet_addr(serverAddr);

server_addr.sin_port = htons(serverPort);

if(connect(connSock,(struct sockaddr *) &server_addr,sizeof(server_addr))<0) {

78
printf("talk Client Can't connect \n");

return -1;

printf("Talk Client connect to Talk server \n");

if((pid = fork( )) < 0) {

printf("fork error\n");

return -1;

} else if(pid > 0) {

do_keyboard(connSock);

} else if(pid == 0) {

do_socket(connSock);

close(connSock);

void

do_keyboard(int connSock)

int n;

char sbuf[BUFSIZ];

while((n = read(0, sbuf, BUFSIZ)) > 0) {

if(write(connSock, sbuf, n) != n) {

printf("Talk Server fail in sending\n");

79
}

if(strncmp(sbuf, quit, 4) == 0) {

kill(pid, SIGQUIT);

break;

void

do_socket(int connSock)

int n;

char rbuf[BUFSIZ];

while(1) {

if((n = read(connSock, rbuf, BUFSIZ)) > 0) {

rbuf[n] = '\0';

printf("%s", rbuf);

if(strncmp(rbuf, quit, 4) == 0) {

kill(getppid( ), SIGQUIT);

break;

80
}

</ 소스 >

81
8 장 멀티스레딩 방식의 다중 접속 서버

8.3 Pthread 를 이용한 스레드 생성

8.3.1 pthread_create 함수와 pthread_join 함수

< 소스 pthread_func.c>

//pthread_func.c

#include <stdio.h>

#include <pthread.h>

void *func_pthread(void *);

int

main(int argc, char **argv){

int sts;

pthread_t thread_id;

void *t_return;

if((sts = pthread_create(&thread_id, NULL, func_pthread, NULL)) != 0 ) {

perror("pthread create error\n");

exit(1);

printf("thread %x is created\n", thread_id);

sleep(3);

82
printf("main function exit\n");

return 0;

void *func_pthread(void *arg)

int i;

while(1) {

sleep(1);

printf("thread executing....\n");

</ 소스 >

< 소스 pthread_join_func.c>

//pthread_join_func.c

#include <stdio.h>

#include <pthread.h>

void *

do_sum(void *data)

int i;

int sum = 0;

83
int max = *((int *)data);

for(i = 0; i < max; i++)

sum = sum + i;

printf("%d - Add %d\n", max, i);

sleep(1);

printf("%d - sum(%d)\n", max, sum);

int

main( )

int thr_id;

pthread_t p_thread[3];

int status;

int a = 4;

int b = 5;

int c = 6;

thr_id = pthread_create(&p_thread[0], NULL, do_sum, (void *)&a);

thr_id = pthread_create(&p_thread[1], NULL, do_sum, (void *)&b);

thr_id = pthread_create(&p_thread[2], NULL, do_sum, (void *)&c);

84
pthread_join(p_thread[0], (void **) &status);

pthread_join(p_thread[1], (void **) &status);

pthread_join(p_thread[2], (void **) &status);

printf("programing is end\n");

return 0;

</ 소스 >

8.3.2 스레드에서 전역 변수의 사용

< 소스 pthread_mutex.c>

//pthread_mutex.c

#include <stdio.h>

#include <unistd.h>

#include <pthread.h>

int ncount;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *do_sum1(void *data)

int i;

int n = *((int *)data);

for(i = 0; i < n; i++)

85
printf("sum1 : %d\n", ncount);

pthread_mutex_lock(&mutex);

ncount ++;

pthread_mutex_unlock(&mutex);

sleep(1);

void *do_sum2(void *data)

int i;

int n = *((int *)data);

for(i = 0; i < n; i++)

printf("sum2 : %d\n", ncount);

pthread_mutex_lock(&mutex);

ncount ++;

pthread_mutex_unlock(&mutex);

sleep(1);

int main( )

86
int thr_id;

pthread_t p_thread[2];

int status;

int a;

ncount = 1;

a = 9;

thr_id = pthread_create(&p_thread[0], NULL, do_sum1, (void *) &a);

sleep(1);

a = 10;

thr_id = pthread_create(&p_thread[1], NULL, do_sum2, (void *) &a);

pthread_join(p_thread[0], (void **) &status);

pthread_join(p_thread[1], (void **) &status);

status = pthread_mutex_destroy(&mutex);

printf("programing is end");

return 0;

</ 소스 >

8.4 스레드를 이용한 다중 접속 서버의 구현

< 소스 echo_server_pthread.c>

87
#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <pthread.h>

#define PORT 8090

void *do_echo(void *);

main( )

int connSock, listenSock;

struct sockaddr_in s_addr, c_addr;

int len;

pthread_t pthread1;

int thr_id;

listenSock = socket(PF_INET, SOCK_STREAM, 0);

23

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(PORT);

88
if(bind(listenSock, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

if(listen(listenSock, 5) == -1) {

printf("listen Fail\n");

return -1;

while(1) {

len = sizeof(c_addr);

connSock = accept(listenSock, (struct sockaddr *) &c_addr, &len);

thr_id = pthread_create(&pthread1, NULL, do_echo, (void *)connSock);

void *

do_echo(void *data)

int n;

char rcvBuffer[BUFSIZ];

int connSock = (int)data;

89
while((n = read(connSock, rcvBuffer, sizeof(rcvBuffer))) != 0) {

write(connSock, rcvBuffer, n);

</ 소스 >

8.5 Pthread 를 이용한 talk 프로그램의 구현

8.5.1 서버 프로그램

< 소스 talk_server_pthread.c>

//talk_server_pthread.c

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <signal.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <pthread.h>

void *do_keyboard(void *);

void *do_socket(void *);

char quit[ ] = "exit";

pthread_t pid[2];

90
int

main(int argc, char *argv[ ]) {

int thr_id;

int status;

int listenSock, connSock;

struct sockaddr_in client_addr, server_addr;

int len;

if(argc < 2) {

printf("Usage: talk_server port_num ");

return -1;

if((listenSock=socket(PF_INET, SOCK_STREAM, 0)) < 0) {

printf("Server: Can't open socket\n");

return -1;

bzero((char *) &server_addr, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

server_addr.sin_port = htons(atoi(argv[1]));

91
if(bind(listenSock, (struct sockaddr *) &server_addr, sizeof(server_addr))<0){

printf("talk Server Can't bind \n");

return -1;

listen(listenSock, 1);

len = sizeof(client_addr);

if((connSock = accept(listenSock,(struct sockaddr *) &client_addr, &len))<0){

printf("Talk Server failed in accepting\n");

return -1;

printf("Talk Server accept new request\n");

thr_id = pthread_create(&pid[0], NULL, do_keyboard, (void *)connSock);

thr_id = pthread_create(&pid[1], NULL, do_socket, (void *)connSock);

pthread_join(pid[0], (void **) &status);

pthread_join(pid[1], (void **) &status);

close(listenSock);

close(connSock);

void *

do_keyboard(void *data)

92
{

int n;

char sbuf[BUFSIZ];

int connSock = (int) data;

while((n = read(0, sbuf, BUFSIZ)) > 0) {

if(write(connSock, sbuf, n) != n) {

printf("Talk Server fail in sending\n");

if(strncmp(sbuf, quit, 4) == 0) {

pthread_kill(pid[1], SIGINT);

break;

void *

do_socket(void *data)

int n;

char rbuf[BUFSIZ];

int connSock = (int) data;

while(1) {

if((n = read(connSock, rbuf, BUFSIZ)) > 0) {

rbuf[n] = '\0';

93
printf("%s", rbuf);

if(strncmp(rbuf, quit, 4) == 0) {

pthread_kill(pid[0], SIGINT);

break;

</ 소스 >

8.5.2 클라이언트 프로그램

< 소스 talk_client_pthread.c>

//talk_client_pthread.c

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <signal.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <pthread.h>

void *do_keyboard(void *);

void *do_socket(void *);

char quit[ ] = "exit";

94
pthread_t pid[2];

int

main(int argc, char *argv[ ]) {

int connSock;

struct sockaddr_in server_addr;

char *serverAddr;

int serverPort;

int thr_id, status;

int len;

if(argc != 3) {

printf("Usage: talk_client server_ip port_num ");

return -1;

} else {

serverAddr = argv[1];

serverPort = atoi(argv[2]);

if((connSock=socket(PF_INET, SOCK_STREAM, 0)) < 0) {

printf("Talk Client Can't open socket\n");

return -1;

bzero((char *) &server_addr, sizeof(server_addr));

95
server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = inet_addr(serverAddr);

server_addr.sin_port = htons(serverPort);

if(connect(connSock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {

printf("talk Client Can't connect \n");

return -1;

printf("Talk Client connect to Talk server \n");

thr_id=pthread_create(&pid[0], NULL, do_keyboard, (void *)connSock);

thr_id=pthread_create(&pid[1], NULL, do_socket, (void *)connSock);

pthread_join(pid[0], (void **) &status);

pthread_join(pid[1], (void **) &status);

close(connSock);

void *

do_keyboard(void *data)

int n;

char sbuf[BUFSIZ];

int connSock = (int) data;

while((n = read(0, sbuf, BUFSIZ)) > 0) {

96
if(write(connSock, sbuf, n) != n) {

printf("Talk Server fail in sending\n");

if(strncmp(sbuf, quit, 4) == 0) {

pthread_kill(pid[1],SIGINT);

break;

void *

do_socket(void *data)

int n;

char rbuf[BUFSIZ];

int connSock = (int) data;

while(1) {

if((n = read(connSock, rbuf, BUFSIZ)) > 0) {

rbuf[n] = '\0';

printf("%s", rbuf);

if(strncmp(rbuf, quit, 4) == 0) {

pthread_kill(pid[0],SIGINT);

break;

97
}

< 소스 >

98
9 장 멀티플렉싱 방식의 다중 접속 서버

9.3 select 함수를 이용한 다중 접속 서버의 구현

< 소스 echo_server_select.c>

//echo_server_select.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define PORT 8090

#define MAX 512

int numClient=0;

int clientSock[MAX];

int getMaxfd(int);

main( )

int connSock, listenSock;

struct sockaddr_in s_addr, c_addr;

int len, i, n;

char rcvBuffer[BUFSIZ];

int maxfd;

99
fd_set read_fds;

listenSock = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(PORT);

if(bind(listenSock, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

if(listen(listenSock, 5) == -1) {

printf("listen Fail\n");

return -1;

while(1) {

maxfd = getMaxfd(listenSock) + 1;

FD_ZERO(&read_fds);

FD_SET(listenSock, &read_fds);

100
for(i = 0; i < numClient; i++)

FD_SET(clientSock[i], &read_fds);

if(select(maxfd, &read_fds, NULL, NULL, NULL) < 0 ) {

printf("select error\n");

exit(-1);

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

if(FD_ISSET(listenSock, &read_fds)) {

connSock=accept(listenSock, (struct sockaddr *) &c_addr, &len);

clientSock[numClient++] = connSock;

for(i = 0; i < numClient; i++) {

if(FD_ISSET(clientSock[i], &read_fds) ) {

if((n=read(clientSock[i], rcvBuffer,sizeof(rcvBuffer)))!=0){

rcvBuffer[n]='\0';

printf("receive - [%s]\n", rcvBuffer);

write(clientSock[i], rcvBuffer, n);

printf("send - [%s]\n", rcvBuffer);

} else {

printf("EOF\n");

close(clientSock[i]);

if(i != numClient-1)

clientSock[i] = clientSock[numClient-1];

101
numClient--;

continue;

int

getMaxfd(int n)

int max = n;

int i;

for(i = 0; i < numClient; i++) {

if(clientSock[i] > max)

max = clientSock[i];

return max;

</ 소스 >

9.4 select 함수를 이용한 talk 프로그램의 구현

9.4.1 서버 프로그램

102
< 소스 talk_server_select.c>

//talk_server_select.c

#include stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define MAX 512

char quit[ ] = "exit";

int numClient=0;

main(int argc, char *argv[ ])

int connSock, listenSock;

struct sockaddr_in s_addr, c_addr;

int len, i, n;

char rcvBuffer[BUFSIZ], sbuf[BUFSIZ];

int maxfd;

if(argc < 2) {

printf("Usage: talk_server port_num");

return -1;

103
fd_set read_fds;

28

listenSock = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(atoi(argv[1]));

if(bind(listenSock, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

if(listen(listenSock, 1) == -1) {

printf("listen Fail\n");

return -1;

connSock=accept(listenSock, (struct sockaddr *) &c_addr, &len);

while(1) {

maxfd = connSock + 1;

FD_ZERO(&read_fds);

FD_SET(0, &read_fds);

FD_SET(connSock, &read_fds);

104
if(select(maxfd, &read_fds, NULL, NULL, NULL) < 0) {

printf("select error\n");

exit(-1);

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

if(FD_ISSET(0, &read_fds)) {

if((n = read(0, sbuf, BUFSIZ)) > 0) {

if(write(connSock, sbuf, n) != n) {

printf("Talk Server fail in sending\n");

if(strncmp(sbuf, quit, 4) == 0) {

break;

if(FD_ISSET(connSock, &read_fds)) {

if((n=read(connSock, rcvBuffer,sizeof(rcvBuffer)))!=0){

rcvBuffer[n]='\0';

printf("receive[%s]\n", rcvBuffer);

if(strncmp(rcvBuffer, quit, 4) == 0) {

break;

105
}

</ 소스 >

9.4.2 클라이언트 프로그램

< 소스 talk_client_select.c>

//talk_client_select.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define MAX 512

char quit[ ] = "exit";

int numClient=0;

main(int argc, char *argv[ ])

int connSock;

struct sockaddr_in s_addr;

int len, i, n;

char rcvBuffer[BUFSIZ], sbuf[BUFSIZ];

int maxfd;

106
if(argc < 3) {

printf("Usage: talk_clinet IP_address port_num");

return -1;

fd_set read_fds;

connSock = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = inet_addr(argv[1]);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(atoi(argv[2]));

if(connect(connSock, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not connect\n");

return -1;

while(1) {

maxfd = connSock + 1;

FD_ZERO(&read_fds);

FD_SET(0, &read_fds);

FD_SET(connSock, &read_fds);

107
if(select(maxfd, &read_fds, NULL, NULL, NULL) < 0) {

printf("select error\n");

exit(-1);

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

if(FD_ISSET(0, &read_fds)) {

if((n = read(0, sbuf, BUFSIZ)) > 0) {

if (write(connSock, sbuf, n) != n) {

printf("Talk Server fail in sending\n");

if(strncmp(sbuf, quit, 4) == 0) {

break;

if(FD_ISSET(connSock, &read_fds)) {

if((n=read(connSock, rcvBuffer,sizeof(rcvBuffer))) !=0) {

rcvBuffer[n]='\0';

printf("receive[%s]\n", rcvBuffer);

if(strncmp(rcvBuffer, quit, 4) == 0) {

break;

108
}

</ 소스 >

109
10 장 MFC 로 talk 프로그램 구현하기

10.1 클라이언트 프로그램

10.1.2 소켓 객체 CSocket::CTalkClientSocket의 생성

< 소스 TalkClientSocket.h>

#pragma once

// CTalkClientSocket 명령 대상입니다 .

classCTalkClientDlg; --①

class CTalkClientSocket : public CSocket

public:

CTalkClientSocket(CTalkClientDlg* pTalkClientDlg); --②

virtual ~CTalkClientSocket( );

public:

CTalkClientDlg*m_pTalkClientDlg; --③

public:

virtual void OnReceive(int nErrorCode); --+④

virtual void OnClose(int nErrorCode); --+

};

</ 소스 >

110
< 소스 TalkClientSocket.cpp>

// TalkClientSocket.cpp : 구현 파일입니다 .

//

#include "stdafx.h"

#include "TalkClient.h"

#include "TalkClientSocket.h"

#include "TalkClientDlg.h" --①

// CTalkClientSocket

CTalkClientSocket::CTalkClientSocket(CTalkClientDlg* pTalkClientDlg) --②

m_pTalkClientDlg = pTalkClientDlg; --③

CTalkClientSocket::~CTalkClientSocket( )

// CTalkClientSocket 멤버 함수

void CTalkClientSocket::OnReceive(int nErrorCode)

// TODO: 여기에 특수화된 코드를 추가 및 / 또는 기본 클래스를 호출합니다 .

m_pTalkClientDlg->ProcessReceive( ); --④

CSocket::OnReceive(nErrorCode);

void CTalkClientSocket::OnClose(int nErrorCode)

111
{

// TODO: 여기에 특수화된 코드를 추가 및 / 또는 기본 클래스를 호출합니다 .

m_pTalkClientDlg->ProcessClose( ); --⑤

CSocket::OnClose(nErrorCode);

</ 소스 >

10.1.3 GUI 설계와 컨트롤에 대한 멤버 함수와 멤버 변수의 추가

< 소스 TalkClientDlg.h>

// TalkClientDlg.h : 헤더 파일

#pragma once

#include "TalkClientSocket.h" --①

#include "afxwin.h"

#include "afxcmn.h"

// CTalkClientDlg 대화 상자

class CTalkClientDlg : public CDialog

// 생성입니다 .

public:

CTalkClientDlg(CWnd* pParent = NULL);// 표준 생성자입니다 .

// 대화 상자 데이터입니다 .

enum { IDD = IDD_TALKCLIENT_DIALOG };

protected:

112
virtual void DoDataExchange(CDataExchange* pDX);// DDX/DDV 지원입니다 .

// 구현입니다 .

protected:

HICON m_hIcon;

// 생성된 메시지 맵 함수

virtual BOOL OnInitDialog( );

afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

afx_msg void OnPaint( );

afx_msg HCURSOR OnQueryDragIcon( );

DECLARE_MESSAGE_MAP( )

public:

CTalkClientSocket* m_pTalkClientSocket; --②

public:

CListBox m_list_box; --③

CEdit m_edit_talk;

CIPAddressCtrl m_ip_address;

CEdit m_edit_port;

CButton m_button_send;

CButton m_button_connect;

CButton m_button_disconnect;

public:

afx_msg void OnBnClickedButtonDisconnect( ); --④

afx_msg void OnBnClickedButtonSend( );

afx_msg void OnBnClickedButtonConnect( );

public:

void ProcessClose(void); --⑤

113
void SetButtonStatus(bool, bool, bool);

void ProcessReceive(void);

};

</ 소스 >

< 소스 TalkClientDlg.cpp>

// TalkClientDlg.cpp : 구현 파일

#include "stdafx.h"

#include "TalkClient.h"

#include "TalkClientDlg.h"

BOOL CTalkClientDlg::OnInitDialog( )

CDialog::OnInitDialog( );

// 시스템 메뉴에 " 정보 ..." 메뉴 항목을 추가합니다 .

// IDM_ABOUTBOX 는 시스템 명령 범위에 있어야 합니다 .

ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);

if(pSysMenu != NULL)

CString strAboutMenu;

114
strAboutMenu.LoadString(IDS_ABOUTBOX);

if(!strAboutMenu.IsEmpty( ))

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

// 이 대화 상자의 아이콘을 설정합니다 . 응용 프로그램의 주 창이 대화 상자가 아닐

경우에는

// 프레임워크가 이 작업을 자동으로 수행합니다 .

SetIcon(m_hIcon, TRUE);// 큰 아이콘을 설정합니다 .

SetIcon(m_hIcon, FALSE);// 작은 아이콘을 설정합니다 .

// TODO: 여기에 추가 초기화 작업을 추가합니다 .

SetButtonStatus(FALSE, TRUE, FALSE);--①

return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE 를 반환합니다 .

void CTalkClientDlg::OnBnClickedButtonConnect( ) --②

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다 .

TCHARstrIP[20];

TCHARstrPort[10];

115
UINTnPort;

m_ip_address.GetWindowTextA(strIP, 20);

m_edit_port.GetWindowTextA(strPort, 10);

nPort = atoi(strPort);

m_pTalkClientSocket = new CTalkClientSocket(this);

if(!m_pTalkClientSocket->Create( )) {

m_list_box.AddString(_T("Fail to Create Socket"));

return;

m_list_box.AddString(_T("Socket Create...."));

if(!m_pTalkClientSocket->Connect(strIP, nPort)){

m_list_box.AddString(_T("Fail to connect"));

return;

m_list_box.AddString(_T("Success to Connect...."));

SetButtonStatus(TRUE, FALSE, TRUE);

void CTalkClientDlg::SetButtonStatus(bool bSend, bool bConnect, bool bDisconnect)--③

m_button_send.EnableWindow(bSend);

m_button_connect.EnableWindow(bConnect);

116
m_button_disconnect.EnableWindow(bDisconnect);

void CTalkClientDlg::OnBnClickedButtonSend( ) --④

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다 .

TCHARstrBuf[100];

m_edit_talk.GetWindowTextA(strBuf, 100);

m_pTalkClientSocket->Send(strBuf, m_edit_talk.GetWindowTextLengthA( ));

m_list_box.SetWindowTextA(strBuf);

m_edit_talk.SetWindowTextA(_T(""));

void CTalkClientDlg::ProcessReceive( ) --⑤

intnRead;

TCHARrcvBuffer[1024];

CString strBuffer = _T("");

nRead = m_pTalkClientSocket->Receive(rcvBuffer, 1024);

strBuffer.Format("%s", rcvBuffer);

m_list_box.AddString(strBuffer.Left(nRead));

void CTalkClientDlg::OnBnClickedButtonDisconnect( ) --⑥

117
{

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다 .

m_pTalkClientSocket->Close( );

delete m_pTalkClientSocket;

SetButtonStatus(FALSE, TRUE, FALSE);

m_list_box.AddString(_T("Close socket"));

void CTalkClientDlg::ProcessClose(void) --⑦

m_list_box.AddString(_T("Server Close"));

m_pTalkClientSocket->Close( );

delete m_pTalkClientSocket;

SetButtonStatus(FALSE, TRUE, FALSE);

m_list_box.AddString(_T("Connection Close"));

</ 소스 >

10.2 서버 프로그램

10.2.2 소켓 객체 CSocket::CListenSocket 과 CSocket::CServiceSocket 의 생성

< 소스 ListenSocket.h>

#pragma once

118
// CListenSocket 명령 대상입니다 .

class CTalkServerDlg; --①

class CListenSocket : public CSocket

public:

CListenSocket(CTalkServerDlg* pTalkServerDlg); --②

virtual ~CListenSocket( );

public:

CTalkServerDlg* m_pTalkServerDlg; --③

public:

virtual void OnAccept(int nErrorCode); --④

};

</ 소스 >

< 소스 ListenSocket.cpp>

// ListenSocket.cpp : 구현 파일입니다 .

//

#include "stdafx.h"

#include "TalkServer.h"

#include "ListenSocket.h"

#include "TalkServerDlg.h" --①

// CListenSocket

119
CListenSocket::CListenSocket(CTalkServerDlg* pTalkServerDlg) --②

m_pTalkServerDlg = pTalkServerDlg; ③

CListenSocket::~CListenSocket( )

// CListenSocket 멤버 함수

void CListenSocket::OnAccept(int nErrorCode)

// TODO: 여기에 특수화된 코드를 추가 및 / 또는 기본 클래스를 호출합니다 .

m_pTalkServerDlg->ProcessAccept( ); --④

CSocket::OnAccept(nErrorCode);

</ 소스 >

< 소스 ServiceSocket.h>

#pragma once

// CServiceSocket 명령 대상입니다 .

class CTalkServerDlg; --①

class CServiceSocket : public CSocket

120
{

public:

CServiceSocket(CTalkServerDlg* pTalkServerDlg); --②

virtual ~CServiceSocket( );

public:

CTalkServerDlg* m_pTalkServerDlg; --③

public:

virtual void OnReceive(int nErrorCode); --④

virtual void OnClose(int nErrorCode); --+

};

</ 소스 >

< 소스 ServiceSocket.cpp>

// ServiceSocket.cpp : 구현 파일입니다 .

#include "stdafx.h"

#include "TalkServer.h"

#include "ServiceSocket.h"

#include "TalkServerDlg.h" --①

// CServiceSocket

CServiceSocket::CServiceSocket(CTalkServerDlg* pTalkServerDlg) --②

m_pTalkServerDlg = pTalkServerDlg; ③

CServiceSocket::~CServiceSocket( )

121
{

// CServiceSocket 멤버 함수

void CServiceSocket::OnReceive(int nErrorCode)

// TODO: 여기에 특수화된 코드를 추가 및 / 또는 기본 클래스를 호출합니다 .

m_pTalkServerDlg->ProcessReceive(this); --④

CSocket::OnReceive(nErrorCode);

void CServiceSocket::OnClose(int nErrorCode)

// TODO: 여기에 특수화된 코드를 추가 및 / 또는 기본 클래스를 호출합니다 .

m_pTalkServerDlg->ProcessClose( ); --⑤

CSocket::OnClose(nErrorCode);

</ 소스 >

< 소스 TalkServerDlg.h>

// TalkServerDlg.h : 헤더 파일

#pragma once

#include "afxwin.h"

#include "ListenSocket.h" --①

#include "ServiceSocket.h" --+

122
// CTalkServerDlg 대화 상자

class CTalkServerDlg : public CDialog

// 생성입니다 .

public:

CTalkServerDlg(CWnd* pParent = NULL);// 표준 생성자입니다 .

// 대화 상자 데이터입니다 .

enum { IDD = IDD_TALKSERVER_DIALOG };

protected:

virtual void DoDataExchange(CDataExchange* pDX);// DDX/DDV 지원입니다 .

// 구현입니다 .

protected:

HICON m_hIcon;

// 생성된 메시지 맵 함수

virtual BOOL OnInitDialog( );

afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

afx_msg void OnPaint( );

afx_msg HCURSOR OnQueryDragIcon( );

DECLARE_MESSAGE_MAP( )

public:

CServiceSocket* m_pServiceSocket; --②

CListenSocket* m_pListenSocket;

123
public:

CListBox m_list_talk; --③

CEdit m_edit_talk;

CEdit m_edit_port;

CButton m_button_send;

CButton m_button_start;

CButton m_button_stop;

public:

void ProcessAccept(void); --④

void ProcessReceive(CServiceSocket*);

void ProcessClose(void);

void SetButtonStatus(bool bSend, bool bStart, bool bStop);

public:

afx_msg void OnBnClickedButtonSend( ); --⑤

afx_msg void OnBnClickedButtonStart( );

afx_msg void OnBnClickedButtonStop( );

};

</ 소스 >

< 소스 TalkServerDlg.cpp>

// TalkServerDlg.cpp : 구현 파일

//

#include "stdafx.h"

#include "TalkServer.h"

#include "TalkServerDlg.h"

124
BOOL CTalkServerDlg::OnInitDialog( )

CDialog::OnInitDialog( );

// 시스템 메뉴에 " 정보 ..." 메뉴 항목을 추가합니다 .

// IDM_ABOUTBOX 는 시스템 명령 범위에 있어야 합니다 .

ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);

if(pSysMenu != NULL)

CString strAboutMenu;

strAboutMenu.LoadString(IDS_ABOUTBOX);

if(!strAboutMenu.IsEmpty( ))

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

// 이 대화 상자의 아이콘을 설정합니다 . 응용 프로그램의 주 창이 대화 상자가 아닐

경우에는

// 프레임워크가 이 작업을 자동으로 수행합니다 .

SetIcon(m_hIcon, TRUE);// 큰 아이콘을 설정합니다 .

125
SetIcon(m_hIcon, FALSE);// 작은 아이콘을 설정합니다 .

// TODO: 여기에 추가 초기화 작업을 추가합니다 .

SetButtonStatus(FALSE, TRUE, FALSE); --①

return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE 를 반환합니다 .

void CTalkServerDlg::OnBnClickedButtonStart( ) --②

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다 .

UINTnPort;

TCHARstrPort[10];

m_edit_port.GetWindowTextA(strPort, 10);

nPort = atoi(strPort);

m_pListenSocket = new CListenSocket(this);

if(!m_pListenSocket->Create(nPort)) {

m_list_talk.AddString(_T("Fail to create socket"));

return;

m_list_talk.AddString("Success to Create Socket....");

if(!m_pListenSocket->Listen( )) {

m_list_talk.AddString(_T("Fail to Listen Socket"));

126
return;

m_list_talk.AddString("Listen Socket....");

SetButtonStatus(FALSE, FALSE, TRUE);

void CTalkServerDlg::ProcessAccept(void) --③

m_pServiceSocket = new CServiceSocket(this);

m_pListenSocket->Accept(*m_pServiceSocket);

m_list_talk.AddString("Connection Accept....");

SetButtonStatus(TRUE, FALSE, TRUE);

void CTalkServerDlg::ProcessReceive(CServiceSocket* pServiceSocket) --④

intnRead;

TCHARstrRecvBuffer[1024];

CStringstrBuffer = _T("");

if((nRead = pServiceSocket->Receive(strRecvBuffer, 1024)) > 0) {

strBuffer.Format("%s", strRecvBuffer);

m_list_talk.AddString(strBuffer.Left(nRead));

127
}

void CTalkServerDlg::OnBnClickedButtonSend( ) --⑤

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다 .

TCHARstrSndBuffer[1024];

m_edit_talk.GetWindowTextA(strSndBuffer, 1024);

m_pServiceSocket->Send(strSndBuffer, (int)strlen(strSndBuffer));

m_edit_talk.SetWindowTextA(_T(""));

void CTalkServerDlg::SetButtonStatus(bool bSend, bool bStart, bool bStop) --⑥

m_button_send.EnableWindow(bSend);

m_button_start.EnableWindow(bStart);

m_button_stop.EnableWindow(bStop);

void CTalkServerDlg::OnBnClickedButtonStop( ) --⑦

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다 .

m_pListenSocket->Close( );

m_pServiceSocket->Close( );

128
m_list_talk.AddString(_T("Close Socket"));

delete m_pListenSocket;

delete m_pServiceSocket;

SetButtonStatus(FALSE, TRUE, FALSE);

void CTalkServerDlg::ProcessClose(void) --⑧

m_pServiceSocket->Close( );

m_list_talk.AddString(_T("Client Close Socket"));

delete m_pServiceSocket;

SetButtonStatus(FALSE, FALSE, TRUE);

</ 소스 >

129
PART 4 TCP 내부 동작과 Raw 소켓

11 장 TCP 내부 동작

11.1 TCP 상태 변화

11.1.1 연결 준비 단계

< 소스 port_stat.c>

//port_stat.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

main(int argc, char **argv)

int c_socket, s_socket;

struct sockaddr_in s_addr, c_addr;

int len;

char greeting[ ] = "TCP state test";

if(argc != 2) {

fprintf(stderr, "usage: TCPserver port_number\n");

exit -1;

130
s_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(atoi(argv[1]));

if(bind(s_socket, (struct sockaddr *) &s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

if(listen(s_socket, 5) == -1) {

printf("listen Fail\n");

return -1;

while(1) {

len = sizeof(c_addr);

c_socket = accept(s_socket, (struct sockaddr *) &c_addr, &len);

write(c_socket, greeting, strlen(greeting));

</ 소스 >

131
11.2 TCP 소켓 옵션

< 소스 sock_opt.c>

//sock_opt.c

#include <sys/socket.h>

#include <stdio.h>

int

main( )

int sock;

int val, len;

struct sock_opts {

const char *opt_str;

int opt_level;

int opt_name;

} sock_opts[ ] = {

{ "SO_BROADCAST", SOL_SOCKET, SO_BROADCAST },

{ "SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE },

{ "SO_LINGER", SOL_SOCKET, SO_LINGER },

{ "SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR },

{ "SO_DONTROUTE", SOL_SOCKET, SO_DONTROUTE },

{ "SO_RCVBUF", SOL_SOCKET, SO_RCVBUF },

{ "SO_SNDBUF", SOL_SOCKET, SO_SNDBUF },

{ "SO_TYPE", SOL_SOCKET, SO_TYPE },

132
{ NULL, 0, 0 }

};

struct sock_opts *ptr;

sock = socket(AF_INET, SOCK_STREAM, 0);

for(ptr = sock_opts; ptr->opt_str != NULL; ptr++) {

len = sizeof(val);

getsockopt(sock, ptr->opt_level, ptr->opt_name, (void *) &val, &len);

35

printf("%s :\t%d\n", ptr->opt_str, val);

</ 소스 >

133
12 장 Raw 소켓

12.2 TCP SYN 포트 스캔 프로그램의 구현

< 소스 cksum_in.c>

unsigned short

cksum_in(unsigned short *addr, int len)

unsigned long sum = 0;

unsigned short answer = 0;

unsigned short *w = addr;

int nleft = len;

while(nleft > 1) {

sum += *w++;

if(sum & 0x80000000)

sum = (sum & 0xffff) + (sum >> 16);

nleft -= 2;

if(nleft == 1) {

*(unsigned char *)(&answer) = *(unsigned char *)w;

sum += answer;

while(sum >> 16)

134
sum = (sum & 0xffff) + (sum >> 16);

return (sum==0xffff)?sum:~sum;

</ 소스 >

< 소스 read_packet.c>

// read_packet.c

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <netinet/in.h>

#include <netdb.h>

#include <netinet/ip.h>

#include <netinet/tcp.h>

#include <sys/socket.h>

void print_ip(struct iphdr *);

void print_tcp(struct tcphdr *);

main( )

int sd;

int len;

int rx_packet_size = sizeof(struct iphdr) + sizeof(struct tcphdr);

char *rx_packet = malloc(rx_packet_size);

135
struct tcphdr *rx_tcph;

struct iphdr *rx_iph;

struct in_addr s_addr, d_addr;

struct sockaddr_in local, remote;

struct servent *serv;

if((sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {

printf("socket open error\n");

exit(-1);

while(1) {

bzero(rx_packet, rx_packet_size);

len = sizeof(local);

if(recvfrom(sd,rx_packet,rx_packet_size,0x0,(struct sockaddr *)&local, &len)<0) {

printf("recvfrom error\n");

exit(-2);

rx_iph = (struct iphdr *)(rx_packet);

rx_tcph = (struct tcphdr *)(rx_packet + rx_iph->ihl * 4);

print_ip(rx_iph);

136
print_tcp(rx_tcph);

close(sd);

void

print_ip(struct iphdr *iph)

printf("[IP HEADER] VER: %1u HL : %2u Protocol : %3u ", iph->version, iph->ihl,

iph->protocol);

printf("SRC IP: %15s ", inet_ntoa(*(struct in_addr *)&iph->saddr));

printf("DEST IP: %15s \n", inet_ntoa(*(struct in_addr *)&iph->daddr));

void

print_tcp(struct tcphdr *tcph)

printf("[TCP HEADER] src port: %5u dest port : %5u ", ntohs(tcph->source),

ntohs(tcph->dest));

(tcph->urg == 1)?printf("U"):printf("-");

(tcph->ack == 1)?printf("A"):printf("-");

(tcph->psh == 1)?printf("P"):printf("-");

(tcph->rst == 1)?printf("R"):printf("-");

(tcph->syn == 1)?printf("S"):printf("-");

137
(tcph->fin == 1)?printf("F"):printf("-");

printf("\n\n");

</ 소스 >

< 소스 port_scan_sys.c>

//syn_port_scan.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <netinet/in.h>

#include <netdb.h>

#include <netinet/ip.h>

#include <netinet/tcp.h>

#include <sys/socket.h>

#define START_PORT 80

#define END_PORT 90

#define LOCAL_IP "203.249.39.141" // 자신의 IP 주소로 수정해야 함

#define LOCAL_PORT 9000 // 발신 포트 번호

unsigned short cksum_in(unsigned short *, int);

struct pseudohdr {

unsigned long s_addr;

unsigned long d_addr;

char zero;

138
unsigned char protocol;

unsigned short length;

};

main(int argc, char *argv[ ])

unsigned long target;

int portNum;

struct hostent *h;

if(argc < 2) {

printf("usage : portscan domain_name\n");

exit(-1);

if((target = inet_addr(argv[1])) == -1) {

h = gethostbyname(argv[1]);

if(!h) {

printf("gethostbyname error\n");

return 4;

target = ((struct in_addr*)h->h_addr)->s_addr;

for(portNum = START_PORT; portNum <= END_PORT; portNum++) {

139
printf("port %d scanning..", portNum);

scan_syn_port(target, portNum);

scan_syn_port(unsigned long target, int port)

int sd;

int on = 1;

int len;

int tx_packet_size = sizeof(struct iphdr) + sizeof(struct tcphdr) + sizeof(struct

pseudohdr);

int rx_packet_size = sizeof(struct iphdr) + sizeof(struct tcphdr);

char *rx_packet = (char *)malloc(rx_packet_size);

char *tx_packet = (char *)malloc(tx_packet_size);

struct tcphdr *tcph, *rx_tcph;

struct iphdr *iph, *rx_iph;

struct pseudohdr *pseudoh;

struct in_addr s_addr, d_addr;

struct sockaddr_in local, remote;

struct servent *serv;

140
iph = (struct iphdr *)(tx_packet);

tcph = (struct tcphdr *)(tx_packet + sizeof(struct iphdr));

pseudoh = (struct pseudohdr *)(tx_packet + sizeof(struct iphdr) + sizeof(struct

tcphdr));

78

if((sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {

printf("socket open error\n"); exit(-1);

if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {

printf("set socket option error\n"); exit(-2);

memset(tx_packet, 0, tx_packet_size);

d_addr.s_addr = target;

s_addr.s_addr = inet_addr(LOCAL_IP);

pseudoh->s_addr = s_addr.s_addr;

pseudoh->d_addr = d_addr.s_addr;

pseudoh->protocol = IPPROTO_TCP;

pseudoh->zero = 0;

pseudoh->length = htons(sizeof(struct tcphdr));

tcph->source = htons(LOCAL_PORT);

tcph->dest = htons(port);

141
tcph->seq = htons(random()%time(NULL));

tcph->ack_seq = 0;

tcph->doff = 5;

tcph->res1 = 0;

tcph->fin = 0;

tcph->syn = 1;

tcph->rst = 0;

tcph->psh = 0;

tcph->ack = 0;

tcph->urg = 0;

tcph->window = htons(1024);

tcph->check = (unsigned short)cksum_in((unsigned short *)tcph, (sizeof(struct

tcphdr) + sizeof(struct pseudohdr)));

iph->ihl = 5;

iph->version = 4;

iph->tos = 0;

iph->tot_len = htons(tx_packet_size) - sizeof(struct pseudohdr);

iph->id = 0;

iph->frag_off = 0;

iph->ttl = IPDEFTTL;

iph->protocol = IPPROTO_TCP;

iph->saddr = s_addr.s_addr;

iph->daddr = d_addr.s_addr;

iph->check = (unsigned short)cksum_in((unsigned short *)iph, sizeof(struct iphdr));

142
remote.sin_family = PF_INET;

remote.sin_addr = d_addr;

remote.sin_port = htons(port);

remote.sin_port = 0;

if(sendto(sd, tx_packet, (tx_packet_size - sizeof(struct pseudohdr)), 0x0, (struct

sockaddr *)&remote, sizeof(remote)) < 0) {

printf("send error\n"); exit(-3);

printf("[tx] %u->%u ", ntohs(tcph->source), ntohs(tcph->dest));

(tcph->urg == 1)?printf("U"):printf("-");

(tcph->ack == 1)?printf("A"):printf("-");

(tcph->psh == 1)?printf("P"):printf("-");

(tcph->rst == 1)?printf("R"):printf("-");

(tcph->syn == 1)?printf("S"):printf("-");

(tcph->fin == 1)?printf("F"):printf("-");

while(recvfrom(sd, rx_packet, rx_packet_size, 0x0, (struct sockaddr *)&local, &len) >0

){

rx_iph = (struct iphdr *)(rx_packet);

rx_tcph = (struct tcphdr *)(rx_packet + rx_iph->ihl * 4);

if( rx_iph->saddr != iph->daddr) continue;

143
if((ntohs(tcph->source) == ntohs(rx_tcph->dest)) && (ntohs(tcph->dest) ==

ntohs(rx_tcph->source))){

printf("[rx] %u->%u ", ntohs(rx_tcph->source), ntohs(rx_tcph->dest));

(rx_tcph->urg == 1)?printf("U"):printf("-");

(rx_tcph->ack == 1)?printf("A"):printf("-");

(rx_tcph->psh == 1)?printf("P"):printf("-");

(rx_tcph->rst == 1)?printf("R"):printf("-");

(rx_tcph->syn == 1)?printf("S"):printf("-");

(rx_tcph->fin == 1)?printf("F"):printf("-");

if(rx_tcph->syn == 1 && rx_tcph->ack == 1) {

serv = getservbyport(htons(port), "tcp");

printf(" port[%d] open/%s \n", ntohs(rx_tcph->source), serv-

>s_name);

} else if (rx_tcph->rst == 1) {

printf(" *\n");

} else {

printf("protocol error\n"); exit(-1);

break;

close(sd);

144
unsigned short

cksum_in(unsigned short *addr, int len)

unsigned long sum = 0;

unsigned short answer = 0;

unsigned short *w = addr;

int nleft = len;

while(nleft > 1) {

sum += *w++;

if(sum & 0x80000000)

sum = (sum & 0xffff) + (sum >> 16);

nleft -= 2;

if(nleft == 1) {

*(unsigned char *)(&answer) = *(unsigned char *)w;

sum += answer;

while(sum >> 16)

sum = (sum & 0xffff) + (sum >> 16);

return(sum==0xffff)?sum:~sum;

145
</ 소스 >

< 소스 my_ping.c>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/socket.h>

#include <netinet/in_systm.h>

#include <netinet/in.h>

#include <netinet/ip.h>

#include <netinet/ip_icmp.h>

#include <signal.h>

void sig_alrm(int);

void send_msg(void);

void handlePing(void);

unsigned short cksum_in(unsigned short *, int);

void tv_sub(struct timeval *, struct timeval *);

struct timeval *tvsend, tvrecv;

int sd;

pid_t pid;

int nsent = 0;

struct sockaddr_in sasend;

struct sockaddr_in sarecv;

146
int salen;

main(int argc, char *argv[ ])

if(argc != 2) {

printf("usage : ping doman_name\n");

exit(-1);

bzero((char *)&sasend, sizeof(sasend));

sasend.sin_family = AF_INET;

sasend.sin_addr.s_addr = inet_addr(argv[1]);

salen = sizeof(sasend);

pid = getpid( ) & 0xffff; // ICMP ID (16 bits)

handlePing( );

void

handlePing(void)

int len, hlen, icmplen;

struct timeval tval;

char rbuf[1500];

fd_set readfd;

147
struct iphdr *iph;

struct icmp *icmp;

double rtt;

signal(SIGALRM, sig_alrm);

if((sd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {

printf("socket open error\n");

exit(-1);

sig_alrm(SIGALRM);

for( ;;) {

if((len = recvfrom(sd, rbuf, sizeof(rbuf), 0, NULL, NULL)) < 0) {

printf("read error\n");

exit (-1);

iph = (struct iphdr *)rbuf;

hlen = iph->ihl * 4;

if(iph->protocol != IPPROTO_ICMP)

return;

148
if(iph->saddr == sasend.sin_addr.s_addr) {

icmp = (struct icmp *)(rbuf + hlen);

icmplen = len - hlen;

if(icmp->icmp_type == ICMP_ECHOREPLY) {

if(icmp->icmp_id != pid)

return;

gettimeofday(&tvrecv, NULL);

tvsend = (struct timeval *) icmp->icmp_data;

tv_sub(&tvrecv, tvsend);

rtt = tvrecv.tv_sec * 1000.0 + tvrecv.tv_usec / 1000.0;

printf("%d byte form **: seq= %u, ttl=%d, rtt=%.3f ms\n",

icmplen, icmp->icmp_seq, iph->ttl, rtt);

void

sig_alrm(int signo)

send_msg( );

149
alarm(1);

return;

void

send_msg(void)

int len;

struct icmp *icmp;

char sendbuf[1500];

int datalen = 56;

icmp = (struct icmp *) sendbuf;

icmp->icmp_type = ICMP_ECHO;

icmp->icmp_code = 0;

icmp->icmp_id = pid;

icmp->icmp_seq = nsent++;

memset(icmp->icmp_data, 0xa5, datalen);

gettimeofday((struct timeval *) icmp->icmp_data, NULL );

len = 8 + datalen;

icmp->icmp_cksum = 0;

icmp->icmp_cksum = cksum_in((unsigned short *)icmp, len);

150
sendto(sd, sendbuf, len, 0, (struct sockaddr *)&sasend, salen);

void

tv_sub(struct timeval *out, struct timeval *in)

if((out->tv_usec -= in->tv_usec) < 0) {

--out->tv_sec;

out->tv_usec += 1000000;

out->tv_sec -= in->tv_sec;

unsigned short

cksum_in(unsigned short *addr, int len)

unsigned long sum = 0;

unsigned short answer = 0;

unsigned short *w = addr;

int nleft = len;

while(nleft > 1) {

sum += *w++;

if(sum & 0x80000000)

sum = (sum & 0xffff) + (sum >> 16);

nleft -= 2;

151
}

if(nleft == 1) {

*(unsigned char *)(&answer) = *(unsigned char *)w;

sum += answer;

while(sum >> 16)

sum = (sum & 0xffff) + (sum >> 16);

return(sum==0xffff)?sum:~sum;

</ 소스 >

152
PART 5 프로젝트로 실습하기

13 장 프로젝트 - 웹 서버

13.3 웹 서버의 구현

13.3.4 웹 클라이언트 프로그램의 구현

< 소스 webClient.c>

//webClient.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <unistd.h>

#define BUF_LEN 128

int main(int argc, char *argv[ ])

int s, n, len_in, len_out;

struct sockaddr_in server_addr;

char *haddr;

char buf[BUF_LEN+1];

int port;

if(argc==3) {

153
port=80;

} else if(argc==4) {

port=atoi(argv[3]);

} else {

printf("usage : webClient server_addr URL [port_number]");

return -1;

haddr=argv[1];

if((s=socket(PF_INET, SOCK_STREAM, 0)) < 0) {

printf("can not create socket\n");

return -1;

memset(&server_addr, 0, sizeof(server_addr));

server_addr.sin_family=AF_INET;

server_addr.sin_addr.s_addr=inet_addr(haddr);

server_addr.sin_port=htons(port);

if(connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {

printf("can not connect");

return -1;

sprintf(buf, "GET %s HTTP/1.0\r\n\r\n", argv[2]);

write(s, buf, strlen(buf));

154
memset(buf, 0, sizeof(buf));

while((n = read(s, buf, BUF_LEN)) > 0) {

printf("%s", buf);

memset(buf, 0, sizeof(buf));

close(s);

</ 소스 >

13.3.5 fork 함수를 이용한 웹 서버 프로그램

< 소스 webServer_fork.c>

//webServer_fork.c

#include <stdio.h>

#include <string.h>

#include <fcntl.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/resource.h>

#include <netinet/in.h>

#include <signal.h>

#include <sys/stat.h>

#define LOG 100

#define ERROR 200

155
#define CODE200 200

#define CODE404 404

#define PHRASE200 "OK"

#define PHRASE404 "FILE NOT FOUND"

char documentRoot[ ] = "/usr/local/apache/htdocs";

void do_web(int);

void web_log(int, char[ ], char[ ], int);

int log_fd;

int

main(int argc, char *argv[ ]) {

struct sockaddr_in s_addr, c_addr;

int s_sock, c_sock;

int len, len_out;

unsigned short port;

int status;

struct rlimit resourceLimit;

int i;

int pid;

if(argc != 2){

printf("usage: webServer port_number");

return -1;

156
}

if(fork( ) != 0)

return 0; // parent return to shell

(void)signal(SIGCLD, SIG_IGN); // ignore child death

(void)signal(SIGHUP, SIG_IGN); // ignore terminal hangup

resourceLimit.rlim_max = 0;

status = getrlimit(RLIMIT_NOFILE, &resourceLimit);

for(i = 0; i < resourceLimit.rlim_max; i++) {

close(i);

web_log(LOG, "STATUS", "web server start", getpid( ));

if((s_sock=socket(PF_INET, SOCK_STREAM, 0))<0){

web_log(ERROR, "SYSCALL", "web server listen sockek open error", s_sock);

port=atoi(argv[1]);

if(port > 60000)

web_log(ERROR, "ERROR", "invalid port number", port);

66

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_family = AF_INET;

157
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_port = htons(port);

if(bind(s_sock, (struct sockaddr *) &s_addr, sizeof(s_addr)) <0)

web_log(ERROR, "ERROR", "server cannot bind", 0);

listen(s_sock, 10);

while(1){

len = sizeof(c_addr);

if((c_sock = accept(s_sock, (struct sockaddr *) &c_addr, &len)) < 0)

web_log(ERROR, "ERROR", "server accept error", 0);

if((pid = fork( )) < 0) {

web_log(ERROR, "ERROR", "server fork error", 0);

} else if(pid == 0) {

close(s_sock);

do_web(c_sock);

} else {

close(c_sock);

void

do_web(int c_sock)

158
{

char sndBuf[BUFSIZ+1], rcvBuf[BUFSIZ+1];

char uri[100], c_type[20];;

int len;

int len_out;

int n, i;

char *p;

char method[10], f_name[20];

char phrase[20] = "OK";

int code = 200;

int fd; // file discriptor

char file_name[20];

char ext[20];

struct stat sbuf;

struct {

char *ext;

char *filetype;

} extensions [ ] = {

{"gif", "image/gif" },

{"jpg", "image/jpeg"},

{"jpeg","image/jpeg"},

159
{"png", "image/png" },

{"zip", "image/zip" },

{"gz", "image/gz" },

{"tar", "image/tar" },

{"htm", "text/html" },

{"html","text/html" },

{0,0} };

memset(rcvBuf, 0, sizeof(rcvBuf));

if((n = read(c_sock, rcvBuf, BUFSIZ)) <= 0)

web_log(ERROR, "ERROR", "can not receive data from web browser", n);

web_log(LOG, "REQUEST", rcvBuf, n);

p = strtok(rcvBuf, " ");

if(strcmp(p, "GET") && strcmp(p, "get"))

web_log(ERROR, "ERROR", "Only get method can support", 0);

p = strtok(NULL, " ");

if(!strcmp(p, "/"))

sprintf(uri, "%s/index.html", documentRoot);

else

sprintf(uri, "%s%s", documentRoot, p);

strcpy(c_type, "text/plain");

for(i=0; extensions[i].ext != 0; i++) {

160
len = strlen(extensions[i].ext);

if( !strncmp(uri+strlen(uri)-len, extensions[i].ext, len) ) {

strcpy(c_type, extensions[i].filetype);

break;

if((fd = open(uri, O_RDONLY)) < 0) {

code = CODE404;

strcpy(phrase, PHRASE404);

p = strtok(NULL, "\r\n "); // version

// send Header

sprintf(sndBuf, "HTTP/1.0 %d %s\r\n", code, phrase);

n = write(c_sock, sndBuf, strlen(sndBuf));

web_log(LOG, "RESPONSE", sndBuf, getpid( ));

sprintf(sndBuf, "content-type: %s\r\n\r\n", c_type);

n = write(c_sock, sndBuf, strlen(sndBuf));

web_log(LOG, "RESPONSE", sndBuf, getpid( ));

if(fd >=0 ) {

while((n = read(fd, rcvBuf, BUFSIZ)) > 0) {

write(c_sock, rcvBuf, n);

161
}

close(c_sock);

exit(-1);

void

web_log(int type, char s1[ ], char s2[ ], int n)

int log_fd;

char buf[BUFSIZ];

if(type == LOG) {

sprintf(buf, "STATUS %s %s %d\n", s1, s2, n);

} else if(type == ERROR) {

sprintf(buf, "ERROR %s %s %d\n", s1, s2, n);

if((log_fd = open("web.log", O_CREAT|O_WRONLY|O_APPEND, 0644)) >= 0) {

write(log_fd, buf, strlen(buf));

close(log_fd);

if(type == ERROR) exit(-1);

162
}

</ 소스 >

13.3.6 스레드를 이용한 웹 서버 프로그램

< 소스 webServer_thread.c>

//webServer_thread.c

#include <stdio.h>

#include <string.h>

#include <fcntl.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/resource.h>

#include <pthread.h>

#include <netinet/in.h>

#include <signal.h>

#include <sys/stat.h>

#define LOG 100

#define ERROR 200

#define CODE200 200

#define CODE404 404

#define PHRASE200 "OK"

#define PHRASE404 "FILE NOT FOUND"

char documentRoot[ ] = "/usr/local/apache/htdocs";

163
void *do_web(void *);

void web_log(int, char[ ], char[ ], int);

pthread_t tid;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int log_fd;

int

main(int argc, char *argv[ ]) {

struct sockaddr_in s_addr, c_addr;

int s_sock, c_sock;

int len, len_out;

unsigned short port;

int status;

struct rlimit resourceLimit;

int i, res;

int pid;

if(argc != 2){

printf("usage: webServer_thread port_number");

return -1;

if(fork( ) != 0)

return 0; // parent return to shell

164
(void)signal(SIGCLD, SIG_IGN); // ignore child death

(void)signal(SIGHUP, SIG_IGN); // ignore terminal hangup

resourceLimit.rlim_max = 0;

status = getrlimit(RLIMIT_NOFILE, &resourceLimit);

for(i = 0; i < resourceLimit.rlim_max; i++) {

close(i);

web_log(LOG, "STATUS", "web server start", getpid( ));

if((s_sock=socket(PF_INET, SOCK_STREAM, 0))<0){

web_log(ERROR, "SYSCALL", "web server listen sockek open error", s_sock);

port=atoi(argv[1]);

if(port > 60000)

web_log(ERROR, "ERROR", "invalid port number", port);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_port = htons(port);

if(bind(s_sock, (struct sockaddr *) &s_addr, sizeof(s_addr)) <0)

165
web_log(ERROR, "ERROR", "server cannot bind", 0);

listen(s_sock, 10);

while(1){

len = sizeof(c_addr);

if((c_sock = accept(s_sock, (struct sockaddr *) &c_addr, &len)) < 0)

web_log(ERROR, "ERROR", "server accept error", 0);

85

res = pthread_create(&tid, NULL, do_web, (void *)c_sock);

void *

do_web(void *arg)

int c_sock = (int) arg;

char sndBuf[BUFSIZ+1], rcvBuf[BUFSIZ+1];

char uri[100], c_type[20];

int len;

int len_out;

int n, i;

char *p;

char method[10], f_name[20];

166
char phrase[20] = "OK";

int code = 200;

int fd; // file discriptor

char file_name[20];

char ext[20];

struct stat sbuf;

struct {

char *ext;

char *filetype;

} extensions [ ] = {

{"gif", "image/gif" },

{"jpg", "image/jpeg"},

{"jpeg","image/jpeg"},

{"png", "image/png" },

{"zip", "image/zip" },

{"gz", "image/gz" },

{"tar", "image/tar" },

{"htm", "text/html" },

{"html","text/html" },

{0,0} };

memset(rcvBuf, 0, sizeof(rcvBuf));

167
if((n = read(c_sock, rcvBuf, BUFSIZ)) <= 0)

web_log(ERROR, "ERROR", "can not receive data from web browser", n);

web_log(LOG, "REQUEST", rcvBuf, n);

p = strtok(rcvBuf, " ");

if(strcmp(p, "GET") && strcmp(p, "get"))

web_log(ERROR, "ERROR", "Only get method can support", 0);

p = strtok(NULL, " ");

if(!strcmp(p, "/"))

sprintf(uri, "%s/index.html", documentRoot);

else

sprintf(uri, "%s%s", documentRoot, p);

strcpy(c_type, "text/plain");

for(i=0; extensions[i].ext != 0; i++) {

len = strlen(extensions[i].ext);

if(!strncmp(uri+strlen(uri)-len, extensions[i].ext, len)) {

strcpy(c_type, extensions[i].filetype);

break;

if((fd = open(uri, O_RDONLY)) < 0) {

code = CODE404;

168
strcpy(phrase, PHRASE404);

p = strtok(NULL, "\r\n "); // version

// send Header

sprintf(sndBuf, "HTTP/1.0 %d %s\r\n", code, phrase);

n = write(c_sock, sndBuf, strlen(sndBuf));

web_log(LOG, "RESPONSE", sndBuf, getpid( ));

sprintf(sndBuf, "content-type: %s\r\n\r\n", c_type);

n = write(c_sock, sndBuf, strlen(sndBuf));

web_log(LOG, "RESPONSE", sndBuf, getpid( ));

if(fd >=0 ) {

while((n = read(fd, rcvBuf, BUFSIZ)) > 0) {

write(c_sock, rcvBuf, n);

close(c_sock);

void

web_log(int type, char s1[ ], char s2[ ], int n)

169
int log_fd;

char buf[BUFSIZ];

if(type == LOG) {

sprintf(buf, "STATUS %s %s %d\n", s1, s2, n);

} else if(type == ERROR) {

sprintf(buf, "ERROR %s %s %d\n", s1, s2, n);

pthread_mutex_lock(&mutex);

if((log_fd = open("web.log", O_CREAT|O_WRONLY|O_APPEND, 0644)) >= 0) {

write(log_fd, buf, strlen(buf));

close(log_fd);

pthread_mutex_unlock(&mutex);

if(type == ERROR) exit(-1);

</ 소스 >

170
14 장 프로젝트 - 채팅 프로그램

14.2.1 서버 프로그램

< 소스 chat_server_select.c>

//chat_server_select.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/select.h>

#define MAX_CLIENT 10

#define CHATDATA 1024

#define INVALID_SOCK -1

int list_c[MAX_CLIENT];

char escape[ ] = "exit";

char greeting[ ] = "Welcome to chatting room\n";

char CODE200[ ] = "Sorry No More Connection\n";

main(int argc, char *argv[ ])

int c_socket, s_socket;

171
struct sockaddr_in s_addr, c_addr;

int len;

int nfds = 0;

int i, j, n;

fd_set read_fds;

char chatData[CHATDATA];

int res;

if(argc < 2) {

printf("usage: %s port_number\n", argv[0]);

exit(-1);

s_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(atoi(argv[1]));

if(bind(s_socket, (struct sockaddr *)&s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

if(listen(s_socket, MAX_CLIENT) == -1) {

172
printf("listen Fail\n");

return -1;

for(i = 0; i < MAX_CLIENT; i++)

list_c[i] = INVALID_SOCK;

while(1) {

nfds = s_socket;

FD_ZERO(&read_fds);

FD_SET(s_socket, &read_fds);

for(i = 0; i < MAX_CLIENT; i++) {

if(list_c[i] != INVALID_SOCK) {

FD_SET(list_c[i], &read_fds);

if(list_c[i] > nfds) nfds = list_c[i];

nfds++;

if(select(nfds, &read_fds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) {

printf("select error\n");

exit(1);

173
if(FD_ISSET(s_socket, &read_fds)) {

len = sizeof(c_addr);

if((c_socket = accept(s_socket, (struct sockaddr *)&c_addr, &len)) > 0)

res = pushClient(c_socket);

if(res < 0) {

write(c_socket, CODE200, strlen(CODE200));

close(c_socket);

} else {

write(c_socket, greeting, strlen(greeting));

89

for(i = 0; i < MAX_CLIENT; i++) {

if((list_c[i] != INVALID_SOCK) && FD_ISSET(list_c[i], &read_fds)) {

memset(chatData, 0, sizeof(chatData));

if((n = read(list_c[i], chatData, sizeof(chatData))) > 0) {

for(j = 0; j < MAX_CLIENT; j++) {

if(list_c[i] != INVALID_SOCK)

write(list_c[j], chatData, n);

if(strstr(chatData, escape) != NULL) {

popClient(list_c[i]);

174
break;

104

int

pushClient(int c_socket) {

int i;

for(i = 0; i < MAX_CLIENT; i++) {

if(list_c[i] == INVALID_SOCK) {

list_c[i] = c_socket;

return i;

if(i == MAX_CLIENT)

return -1;

int

popClient(int s)

175
{

int i;

close(s);

for(i = 0; i < MAX_CLIENT; i++) {

if(s == list_c[i] ) {

list_c[i] = INVALID_SOCK;

break;

return 0;

</ 소스 >

14.2.2 클라이언트 프로그램

< 소스 chat_client_select.c>

//chat_client_select.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/select.h>

176
#define CHATDATA 1024

char escape[ ] = "exit";

char nickname[20];

main(int argc, char *argv[ ])

int c_socket;

struct sockaddr_in c_addr;

int len;

char chatData[CHATDATA];

char buf[CHATDATA];

int nfds;

fd_set read_fds;

int n;

if(argc < 3) {

printf("usgae : %s ip_address port_number\n", argv[0]);

exit(-1);

c_socket = socket(PF_INET, SOCK_STREAM, 0);

memset( &c_addr, 0, sizeof(c_addr) );

c_addr.sin_addr.s_addr = inet_addr(argv[1]);

c_addr.sin_family = AF_INET;

177
c_addr.sin_port = htons(atoi(argv[2]));

printf("Input Nickname : ");

scanf("%s", nickname);

if(connect(c_socket, (struct sockaddr *)&c_addr, sizeof(c_addr)) == -1) {

printf("Can not connect\n");

return -1;

nfds = c_socket + 1;

while(1) {

FD_ZERO(&read_fds);

FD_SET(0, &read_fds); // standard input

FD_SET(c_socket, &read_fds); // from chat server

53

if(select(nfds, &read_fds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) {

printf("select error\n");

exit(1);

if(FD_ISSET(c_socket, &read_fds)) {

memset(chatData, 0, sizeof(chatData));

if((n = read(c_socket, chatData, sizeof(chatData))) > 0 ) {

178
write(1, chatData, n);

65

if(FD_ISSET(0, &read_fds)) {

memset(buf, 0, sizeof(buf));

if((n = read(0, buf, sizeof(buf))) > 0 ) {

sprintf(chatData, "[%s] %s", nickname, buf);

write(c_socket, chatData, strlen(chatData));

if(!strncmp(buf, escape, strlen(escape))) {

break;

close(c_socket);

</ 소스 >

14.3 스레드를 이용한 채팅 프로그램의 구현

14.3.1 서버 프로그램

179
< 소스 chat_server_thread.c>

//chat_server_thread.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <pthread.h>

void *do_chat(void *);

int pushClient(int);

int popClient(int);

pthread_t thread;

pthread_mutex_t mutex;

#define MAX_CLIENT 10

#define CHATDATA 1024

#define INVALID_SOCK -1

int list_c[MAX_CLIENT];

char escape[ ] = "exit";

char greeting[ ] = "Welcome to chatting room\n";

char CODE200[ ] = "Sorry No More Connection\n";

180
main(int argc, char *argv[ ])

int c_socket, s_socket;

struct sockaddr_in s_addr, c_addr;

int len;

int i, j, n;

int res;

if(argc < 2) {

printf("usage: %s port_number\n", argv[0]);

exit(-1);

if(pthread_mutex_init(&mutex, NULL) != 0) {

printf("Can not create mutex\n");

return -1;

s_socket = socket(PF_INET, SOCK_STREAM, 0);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(atoi(argv[1]));

181
if(bind(s_socket, (struct sockaddr *)&s_addr, sizeof(s_addr)) == -1) {

printf("Can not Bind\n");

return -1;

if(listen(s_socket, MAX_CLIENT) == -1) {

printf("listen Fail\n");

return -1;

for(i = 0; i < MAX_CLIENT; i++)

list_c[i] = INVALID_SOCK;

while(1) {

len = sizeof(c_addr);

c_socket = accept(s_socket, (struct sockaddr *) &c_addr, &len);

res = pushClient(c_socket);

if(res < 0) {

write(c_socket, CODE200, strlen(CODE200));

close(c_socket);

} else {

write(c_socket, greeting, strlen(greeting));

pthread_create(&thread, NULL, do_chat, (void *) c_socket);

182
}

void *

do_chat(void *arg)

int c_socket = (int) arg;

char chatData[CHATDATA];

int i, n;

while(1) {

memset(chatData, 0, sizeof(chatData));

if((n = read(c_socket, chatData, sizeof(chatData))) > 0) {

for(i = 0; i < MAX_CLIENT; i++) {

if(list_c[i] != INVALID_SOCK) {

write(list_c[i], chatData, n);

if(strstr(chatData, escape) != NULL) {

popClient(c_socket);

break;

183
int

pushClient(int c_socket) {

int i;

for(i = 0; i < MAX_CLIENT; i++) {

pthread_mutex_lock(&mutex);

if(list_c[i] == INVALID_SOCK) {

list_c[i] = c_socket;

pthread_mutex_unlock(&mutex);

return i;

pthread_mutex_unlock(&mutex);

if(i == MAX_CLIENT)

return -1;

122 }

int

popClient(int s)

int i;

close(s);

for(i = 0; i < MAX_CLIENT; i++) {

184
pthread_mutex_lock(&mutex);

if(s == list_c[i]) {

list_c[i] = INVALID_SOCK;

pthread_mutex_unlock(&mutex);

break;

pthread_mutex_unlock(&mutex);

return 0;

</ 소스 >

14.3.2 클라이언트 프로그램

< 소스 chat_client_thread.c>

//chat_client_thread.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/select.h>

#include <pthread.h>

#include <signal.h>

185
#define CHATDATA 1024

void *do_send_chat(void *);

void *do_receive_chat(void *);

pthread_t thread_1, thread_2;

char escape[ ] = "exit";

char nickname[20];

main(int argc, char *argv[ ])

int c_socket;

struct sockaddr_in c_addr;

int len;

char chatData[CHATDATA];

char buf[CHATDATA];

int nfds;

fd_set read_fds;

int n;

if(argc < 3) {

printf("usgae : %s ip_address port_number\n", argv[0]);

exit(-1);

c_socket = socket(PF_INET, SOCK_STREAM, 0);

186
memset(&c_addr, 0, sizeof(c_addr));

c_addr.sin_addr.s_addr = inet_addr(argv[1]);

c_addr.sin_family = AF_INET;

c_addr.sin_port = htons(atoi(argv[2]));

printf("Input Nickname : ");

scanf("%s", nickname);

if(connect(c_socket, (struct sockaddr *) &c_addr, sizeof(c_addr)) == -1) {

printf("Can not connect\n");

return -1;

pthread_create(&thread_1, NULL, do_send_chat, (void *) c_socket);

pthread_create(&thread_2, NULL, do_receive_chat, (void *) c_socket);

pthread_join(thread_1, NULL);

pthread_join(thread_2, NULL);

close(c_socket);

void *

do_send_chat(void *arg)

char chatData[CHATDATA];

187
char buf[CHATDATA];

int n;

int c_socket = (int) arg; // client socket

while(1) {

memset(buf, 0, sizeof(buf));

if((n = read(0, buf, sizeof(buf))) > 0 ) {

sprintf(chatData, "[%s] %s", nickname, buf);

write(c_socket, chatData, strlen(chatData));

if(!strncmp(buf, escape, strlen(escape))) {

pthread_kill(thread_2, SIGINT);

break;

void *

do_receive_chat(void *arg)

char chatData[CHATDATA];

int n;

int c_socket = (int) arg; // client socket

while(1) {

188
memset(chatData, 0, sizeof(chatData));

if((n = read(c_socket, chatData, sizeof(chatData))) > 0 ) {

write(1, chatData, n);

</ 소스 >

14.4 윈도우 기반에서 MFC 로 채팅 서버 프로그램의 구현

14.4.2 소켓 객체 CSocket::CListenSocket 과 CSocket::CServiceSocket 의 생성

< 소스 ListenSocket.h>

#pragma once

// CListenSocket 명령 대상입니다 .

class CChatServerDlg; --①

class CListenSocket : public CSocket

public:

CListenSocket(CChatServerDlg* pChatServerDlg); --②

virtual ~CListenSocket( );

public:

CChatServerDlg* m_pChatServerDlg; --③

public:

189
virtual void OnAccept(int nErrorCode); --④

};

</ 소스 >

< 소스 ListenSocket.cpp>

// ListenSocket.cpp : 구현 파일입니다 .

//

#include "stdafx.h"

#include "ChatServer.h"

#include "ListenSocket.h"

#include "ChatServerDlg.h" --①

// CListenSocket

CListenSocket::CListenSocket(CChatServerDlg* pChatServerDlg) --②

m_pChatServerDlg = pChatServerDlg; ③

CListenSocket::~CListenSocket( )

// CListenSocket 멤버 함수

void CListenSocket::OnAccept(int nErrorCode)

190
{

// TODO: 여기에 특수화된 코드를 추가 및 / 또는 기본 클래스를 호출합니다 .

m_pChatServerDlg->ProcessAccept( ); --④

CSocket::OnAccept(nErrorCode);

</ 소스 >

< 소스 ServiceSocket.h>

#pragma once

// CServiceSocket 명령 대상입니다 .

class CChatServerDlg; --①

class CServiceSocket : public CSocket

public:

CServiceSocket(CChatServerDlg* pChatServerDlg); --②

virtual ~CServiceSocket( );

public:

CChatServerDlg* m_pChatServerDlg; --③

public:

virtual void OnReceive(int nErrorCode); --④

virtual void OnClose(int nErrorCode); --+

};

</ 소스 >

191
< 소스 ServiceSocket.cpp>

// ServiceSocket.cpp : 구현 파일입니다 .

//

#include "stdafx.h"

#include "ChatServer.h"

#include "ServiceSocket.h"

#include "ChatServerDlg.h" --①

// CServiceSocket

CServiceSocket::CServiceSocket(CChatServerDlg* pChatServerDlg) --②

m_pChatServerDlg = pChatServerDlg; ③

CServiceSocket::~CServiceSocket( )

// CServiceSocket 멤버 함수

void CServiceSocket::OnReceive(int nErrorCode)

// TODO: 여기에 특수화된 코드를 추가 및 / 또는 기본 클래스를 호출합니다 .

m_pChatServerDlg->ProcessReceive( ); --④

192
CSocket::OnReceive(nErrorCode);

void CServiceSocket::OnClose(int nErrorCode)

// TODO: 여기에 특수화된 코드를 추가 및 / 또는 기본 클래스를 호출합니다 .

m_pChatServerDlg->ProcessClose( ); --⑤

CSocket::OnClose(nErrorCode);

</ 소스 >

14.4.3 GUI 설계와 컨트롤에 대한 멤버 함수와 멤버 변수의 추가

< 소스 ChatServerDlg.h>

// ChatServerDlg.h : 헤더 파일

//

#pragma once

#include "afxwin.h"

#include "ListenSocket.h" --①

#include "ServiceSocket.h" --+

// CChatServerDlg 대화 상자

class CChatServerDlg : public CDialog

193
// 생성입니다 .

public:

CChatServerDlg(CWnd* pParent = NULL);// 표준 생성자입니다 .

// 대화 상자 데이터입니다 .

enum { IDD = IDD_CHATSERVER_DIALOG };

protected:

virtual void DoDataExchange(CDataExchange* pDX);// DDX/DDV 지원입니다 .

// 구현입니다 .

protected:

HICON m_hIcon;

// 생성된 메시지 맵 함수

virtual BOOL OnInitDialog( );

afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

afx_msg void OnPaint( );

afx_msg HCURSOR OnQueryDragIcon( );

DECLARE_MESSAGE_MAP( )

public:

CListenSocket* m_pListenSocket; --②

CServiceSocket* m_pServiceSocket; --+

CPtrList m_pServiceSocketList; --③

194
public:

CEdit m_edit_port; --④

CEdit m_edit_status; -- +

CButton m_button_start; --+

CButton m_button_stop; --+

public:

void ProcessAccept(void); --⑤

void ProcessReceive(CServiceSocket* pServiceSocket);

void ProcessClose(CServiceSocket* pServiceSocket);

void SetButtonStatus(bool bStart, bool bStop); --+

public:

afx_msg void OnBnClickedButtonStart( ); --⑥

afx_msg void OnBnClickedButtonStop( ); --+

};

</ 소스 >

< 소스 ChatServerDlg.cpp>

BOOL CChatServerDlg::OnInitDialog( )

CDialog::OnInitDialog( );

// 시스템 메뉴에 " 정보 ..." 메뉴 항목을 추가합니다 .

// IDM_ABOUTBOX 는 시스템 명령 범위에 있어야 합니다 .

ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

ASSERT(IDM_ABOUTBOX < 0xF000);

195
CMenu* pSysMenu = GetSystemMenu(FALSE);

if(pSysMenu != NULL)

CString strAboutMenu;

strAboutMenu.LoadString(IDS_ABOUTBOX);

if(!strAboutMenu.IsEmpty( ))

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

// 이 대화 상자의 아이콘을 설정합니다 . 응용 프로그램의 주 창이 대화 상자가 아닐

// 경우에는 프레임워크가 이 작업을 자동으로 수행합니다 .

SetIcon(m_hIcon, TRUE);// 큰 아이콘을 설정합니다 .

SetIcon(m_hIcon, FALSE);// 작은 아이콘을 설정합니다 .

// TODO: 여기에 추가 초기화 작업을 추가합니다 .

SetButtonStatus(TRUE, FALSE); --①

return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE 를 반환합니다 .

void CChatServerDlg::OnBnClickedButtonStart( )--②

196
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다 .

charstrPort[10];

UINTuPort;

m_pListenSocket = new CListenSocket(this);

m_edit_port.GetWindowText(strPort, 10);

uPort = atoi(strPort);

if(!m_pListenSocket->Create(uPort)) {

m_edit_status.SetWindowText(_T("Fail to Create Socket"));

return;

m_edit_status.SetWindowText(_T("Socket Create"));

if(!m_pListenSocket->Listen( )) {

m_edit_status.SetWindowText(_T("Fail to Listen"));

return;

m_edit_status.SetWindowText(_T("Listening Socket..."));

SetButtonStatus(FALSE, TRUE);

void CChatServerDlg::OnBnClickedButtonStop( )--③

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다 .

POSITIONpos = m_pServiceSocketList.GetHeadPosition( );

197
CServiceSocket* pClient;

while(pos != NULL) {

pClient = (CServiceSocket *)m_pServiceSocketList.GetNext(pos);

pClient->Close( );

delete pClient;

delete m_pListenSocket;

SetButtonStatus(TRUE, FALSE);

void CChatServerDlg::ProcessAccept(void) --④

m_pServiceSocket = new CServiceSocket(this);

if(!m_pListenSocket->Accept(*m_pServiceSocket)) {

m_edit_status.SetWindowText(_T("Fail to Accept"));

return;

m_edit_status.SetWindowText(_T("Accept Connection Request"));

m_pServiceSocketList.AddTail(m_pServiceSocket);

void CChatServerDlg::ProcessReceive(CServiceSocket* pServiceSocket) --⑤

TCHAR rcvBuffer[1024];

198
int nRead;

POSITIONpos = m_pServiceSocketList.GetHeadPosition( );

CServiceSocket* pClient;

nRead = pServiceSocket->Receive(rcvBuffer, 1024);

while(pos != NULL) {

pClient = (CServiceSocket *)m_pServiceSocketList.GetNext(pos);

pClient->Send(rcvBuffer, nRead);

void CChatServerDlg::ProcessClose(CServiceSocket* pServiceSocket) --⑥

POSITION pos;

pos = m_pServiceSocketList.Find(pServiceSocket);

m_pServiceSocketList.RemoveAt(pos);

delete pServiceSocket;

m_edit_status.SetWindowText(_T("Client Disconnect"));

void CChatServerDlg::SetButtonStatus(bool bStart, bool bStop) --⑦

m_button_start.EnableWindow(bStart);

199
m_button_stop.EnableWindow(bStop);

</ 소스 >

200
15 장 프로젝트 - FTP 프로그램

15.2 파일 처리 관련 함수

15.2.1 표준 입출력 함수를 이용한 파일 처리

< 소스 fileRead.c>

//fileRead.c

# include <stdio.h>

main(int argc, char **argv)

int c;

FILE *from;

if(argc != 2) {

fprintf(stderr, "Ussage: a.out file_name\n");

exit(-1);

if((from = fopen(argv[1], "r")) == NULL) {

perror(argv[1]);

exit(1);

while((c = getc(from)) != EOF)

printf("%c", c);

201
fclose(from);

</ 소스 >

< 소스 fileRead_fgets.c>

//fileRead_fgets.c

#include <stdio.h>

main(int argc, char **argv)

char buf[BUFSIZ];

FILE *from, *to;

if(argc != 3) {

fprintf(stderr, "Ussage: a.out in_file_name out_file_name\n");

exit(-1);

if((from = fopen(argv[1], "r")) == NULL) {

perror(argv[1]);

exit(1);

if((to = fopen(argv[2], "a")) == NULL) {

perror(argv[2]);

exit(1);

202
while(fgets(buf, BUFSIZ, from) != NULL)

fputs(buf, to);

fclose(from);

fclose(to);

</ 소스 >

< 소스 fileRead_fread.c>

//fileRead_fread.c

#include <stdio.h>

main(int argc, char **argv)

char buf[BUFSIZ];

FILE *from, *to;

int n;

if(argc != 3) {

fprintf(stderr, "Ussage: a.out in_file_name out_file_name\n");

exit(-1);

if((from = fopen(argv[1], "r")) == NULL) {

perror(argv[1]);

203
exit(1);

if((to = fopen(argv[2], "a")) == NULL) {

perror(argv[2]);

exit(1);

while((n = fread(buf, sizeof(char), BUFSIZ, from)) > 0)

fwrite(buf, sizeof(char), n, to);

fclose(from);

fclose(to);

</ 소스 >

< 소스 fileRead_read.c>

//fileRead_read.c

#include <stdio.h>

#include <sys/file.h>

main(int argc, char **argv)

char buf[BUFSIZ];

int from, to;

int n;

204
if(argc != 3) {

fprintf(stderr, "Ussage: a.out in_file_name out_file_name\n");

exit(-1);

if((from = open(argv[1], O_RDONLY)) < 0) {

perror(argv[1]);

exit(1);

if((to = open(argv[2], O_WRONLY | O_CREAT | O_APPEND, 0644)) < 0) {

perror(argv[2]);

exit(1);

while((n = read(from, buf, sizeof(buf))) > 0)

write(to, buf, n);

close(from);

close(to);

</ 소스 >

15.3 FTP 클라이언트 프로그램의 구현

205
< 소스 ftp_client.c>

//ftp_client.c

// ftp server_address [port]

#include <stdio.h>

#include <string.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <unistd.h>

#include <sys/ioctl.h>

#include <net/if.h>

#define STRLEN 100

#define PORTLEN 28

short cmdPort;

int cmdSock;

int dataSock;

char message[BUFSIZ];

struct _dataChannel {

char ip[STRLEN];

char chaIp[STRLEN];

unsigned short port;

char chaPort[STRLEN];

206
int c_sock;

} dataChannel;

int hash = -1;

int

main(int argc, char *argv[ ])

if(argc == 3)

cmdPort = atoi(argv[2]);

else if(argc == 2)

cmdPort = 21;

else {

fprintf(stderr, "Usage: ftp server_address [port]\n");

exit(-1);

cmdSock = makeConnection(argv[1]);

makeLogin( );

while(1) {

processCommand( );

close(cmdSock);

207
}

int

makeConnection(char *ip)

struct sockaddr_in s_addr;

if((cmdSock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {

fprintf(stderr, "socket open error\n");

exit(-1);

memset(&s_addr, 0, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_addr.s_addr = inet_addr(ip);

s_addr.sin_port = htons(cmdPort);

if(connect(cmdSock, (struct sockaddr *) &s_addr, sizeof(s_addr)) < 0) {

fprintf(stderr, "connection error");

exit(-1);

return (cmdSock);

makeLogin( )

208
char *pUser, *pPass;

int intCode;

char chaCode[STRLEN];

char sndBuf[BUFSIZ];

int n;

pUser = (char *)malloc(sizeof(char) * STRLEN);

memset(pUser, 0, STRLEN);

pPass = (char *)malloc(sizeof(char) * STRLEN);

memset(pPass, 0, STRLEN);

// make user

n = read(cmdSock, message, BUFSIZ);

intCode = getCode(message);

if(intCode == 220) {

printf("User : ");

fgets(pUser, STRLEN, stdin);

pUser[strlen(pUser) - 1] = '\0';

sprintf(sndBuf, "USER %s\r\n", pUser);

write(cmdSock, sndBuf, strlen(sndBuf));

} else {

209
fprintf(stderr, "login error");

exit(-1);

// make password

n = read(cmdSock, message, BUFSIZ);

intCode = getCode(message);

if(intCode == 331) {

pPass = getpass("password : ");

sprintf(sndBuf, "PASS %s\r\n", pPass);

write(cmdSock, sndBuf, strlen(sndBuf));

} else {

fprintf(stderr, "passwd error");

exit(-1);

// Sucess Login

n = read(cmdSock, message, BUFSIZ);

intCode = getCode(message);

if(intCode == 230) {

fprintf(stderr, "Login Success\n");

} else {

fprintf(stderr, "Login Fail\n");

210
exit(-1);

free(pUser); free(pPass);

processCommand( )

char command[BUFSIZ];

char *pCommand;

char chaCmd[STRLEN], chaArg[STRLEN];

int nCmd;

printf("ftp > ");

fgets(command, BUFSIZ, stdin);

if(!strcmp(command, "\n")) return;

if((pCommand = strchr(command, '\n')) != NULL)

*pCommand = '\0';

if((pCommand = strchr(command, ' ')) == NULL) {

strcpy(chaCmd, command);

strcpy(chaArg, "");

} else {

strncpy(chaCmd, command, pCommand - command);

211
chaCmd[pCommand-command] = '\0';

strcpy(chaArg, pCommand + 1);

if(!strcmp(chaCmd, "ls")) {

handle_ls(chaArg);

} else if(!strcmp(chaCmd, "get")) {

handle_get(chaArg);

} else if(!strcmp(chaCmd, "cd")) {

handle_cd(chaArg);

} else if(!strcmp(chaCmd, "quit")) {

handle_quit(chaArg);

exit(1);

} else if(!strcmp(chaCmd, "put")) {

handle_put(chaArg);

} else if(!strcmp(chaCmd, "hash")) {

hash = hash * -1;

(hash > 0 ? printf("hash on\n") : printf("hash off\n"));

} else {

printf("command: ls|cd|get|put||hash|quit\n");

int

handle_quit(char chaArg[ ])

212
{

int intCode;

int n;

char chaCode[STRLEN];

char sndBuf[BUFSIZ];

char rcvBuf[BUFSIZ];

// send QUIT

sprintf(sndBuf, "QUIT %s\r\n", chaArg);

n = write(cmdSock, sndBuf, strlen(sndBuf));

memset(rcvBuf, 0, BUFSIZ);

n = read(cmdSock, rcvBuf, BUFSIZ);

intCode = getCode(rcvBuf);

close(cmdSock);

return (intCode);

int

handle_cd(char chaArg[ ])

int intCode;

int n;

213
char chaCode[STRLEN];

char sndBuf[BUFSIZ];

char rcvBuf[BUFSIZ];

// send CWD

sprintf(sndBuf, "CWD %s\r\n", chaArg);

n = write(cmdSock, sndBuf, strlen(sndBuf));

memset(rcvBuf, 0, BUFSIZ);

n = read(cmdSock, rcvBuf, BUFSIZ);

intCode = getCode(rcvBuf);

return (intCode);

int

handle_put(char chaArg[ ])

char sndBuf[BUFSIZ];

char rcvBuf[BUFSIZ];

char chaCode[STRLEN];

int intCode;

int n, cnt;

int fsize;

// make PORT

214
make_ip( );

sprintf(sndBuf, "PORT %s\r\n", dataChannel.chaPort);

n = write(cmdSock, sndBuf, strlen(sndBuf));

memset(rcvBuf, 0, BUFSIZ);

n = read(cmdSock, rcvBuf, BUFSIZ);

intCode = getCode(rcvBuf);

if(intCode != 200)

return (intCode);

if(!strcmp(chaArg, ""))

return -1;

else if(access(chaArg, F_OK) != 0)

return -1;

// send STOR

sprintf(sndBuf, "STOR %s\r\n", chaArg);

n = write(cmdSock, sndBuf, strlen(sndBuf));

openDataChannel( );

memset(rcvBuf, 0, BUFSIZ);

cnt = 0;

215
while(1) {

n = read(cmdSock, rcvBuf+cnt, 1);

if(*(rcvBuf+cnt) == '\n') break;

cnt++;

intCode = getCode(rcvBuf);

if(intCode == 150) {

sndFile(chaArg);

} else {

return (intCode);

memset(rcvBuf, 0, BUFSIZ);

n = read(cmdSock, rcvBuf, BUFSIZ);

intCode = getCode(rcvBuf);

return (intCode);

int

handle_get(char chaArg[ ])

char sndBuf[BUFSIZ];

char rcvBuf[BUFSIZ];

char chaCode[STRLEN];

216
int intCode;

int n, cnt;

int fsize;

// send SIZE

sprintf(sndBuf, "SIZE %s\r\n", chaArg);

n = write(cmdSock, sndBuf, strlen(sndBuf));

memset(rcvBuf, 0, BUFSIZ);

n = read(cmdSock, rcvBuf, BUFSIZ);

intCode = getCode(rcvBuf);

if(intCode == 213) {

fsize = atoi(rcvBuf+3);

} else {

return (intCode);

if(fsize == 0 || intCode == 550) {

fprintf(stderr, "file error\n");

return (intCode);

// make PORT

make_ip( );

217
sprintf(sndBuf, "PORT %s\r\n", dataChannel.chaPort);

n = write(cmdSock, sndBuf, strlen(sndBuf));

memset(rcvBuf, 0, BUFSIZ);

n = read(cmdSock, rcvBuf, BUFSIZ);

intCode = getCode(rcvBuf);

// send RETR

sprintf(sndBuf, "RETR %s\r\n", chaArg);

n = write(cmdSock, sndBuf, strlen(sndBuf));

openDataChannel( );

memset(rcvBuf, 0, BUFSIZ);

cnt = 0;

while(1) {

n = read(cmdSock, rcvBuf+cnt, 1);

if(*(rcvBuf+cnt) == '\n') break;

cnt++;

intCode = getCode(rcvBuf);

if(intCode == 150) {

rcvFile(fsize, chaArg);

218
} else {

return (intCode);

memset(rcvBuf, 0, BUFSIZ);

n = read(cmdSock, rcvBuf, BUFSIZ);

intCode = getCode(rcvBuf);

return (intCode);

sndFile(char *chaArg)

char sndBuf[BUFSIZ];

FILE *fp;

int n;

fp = fopen(chaArg, "r");

while((n = fread(sndBuf, sizeof(char), BUFSIZ, fp)) > 0) {

write(dataChannel.c_sock, sndBuf, n);

if(hash > 0) printf("#");

printf("\n");

fclose(fp);

219
close(dataChannel.c_sock);

rcvFile(int fsize, char *chaArg)

char rcvBuf[BUFSIZ];

FILE *fp;

int nRecv = 0;

int n;

if((fp = fopen(chaArg, "w+")) == 0)

return (-1);

while(nRecv < fsize) {

n = read(dataChannel.c_sock, rcvBuf, BUFSIZ);

if(hash > 0) printf("#");

fwrite(rcvBuf, n, 1, fp);

nRecv += n;

printf("\n");

fclose(fp);

close(dataChannel.c_sock);

int

220
handle_ls(char chaArg[ ])

char sndBuf[BUFSIZ];

char rcvBuf[BUFSIZ];

char chaCode[STRLEN];

int intCode;

int n, cnt;

make_ip( );

sprintf(sndBuf, "PORT %s\r\n", dataChannel.chaPort);

n = write(cmdSock, sndBuf, strlen(sndBuf));

memset(rcvBuf, 0, BUFSIZ);

n = read(cmdSock, rcvBuf, BUFSIZ);

intCode = getCode(rcvBuf);

if(intCode == 200) {

sprintf(sndBuf, "LIST %s\r\n", chaArg);

write(cmdSock, sndBuf, strlen(sndBuf));

openDataChannel( );

} else

return intCode;

memset(rcvBuf, 0, BUFSIZ);

221
cnt = 0;

while(1) {

n = read(cmdSock, rcvBuf+cnt, 1);

if(*(rcvBuf+cnt) == '\n') break;

cnt++;

intCode = getCode(rcvBuf);

if(intCode == 150) {

rcvData( );

} else {

return intCode;

memset(rcvBuf, 0, BUFSIZ);

n = read(cmdSock, rcvBuf, BUFSIZ);

intCode = getCode(rcvBuf);

return intCode;

rcvData( )

int n = 0;

char rcvBuf[BUFSIZ] = {0, };

222
memset(rcvBuf, 0, BUFSIZ);

while((n = read(dataChannel.c_sock, rcvBuf, BUFSIZ)) > 0) {

printf("%s", rcvBuf);

memset(rcvBuf, 0, BUFSIZ);

close(dataChannel.c_sock);

openDataChannel( )

int option = 8;

int optlen;

struct sockaddr_in data_addr, c_addr;

int len;

if((dataSock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {

fprintf(stderr, "data socket open error\n");

return;

optlen = sizeof(option);

setsockopt(dataSock, SOL_SOCKET, SO_REUSEADDR, &option, optlen);

memset(&data_addr, 0, sizeof(data_addr));

223
data_addr.sin_family = AF_INET;

data_addr.sin_addr.s_addr = inet_addr(dataChannel.ip);

data_addr.sin_port = htons(dataChannel.port);

if(bind(dataSock, (struct sockaddr *) &data_addr, sizeof(data_addr)) == -1) {

fprintf(stderr, "bind error\n");

return;

if(listen(dataSock, 1) == -1) {

fprintf(stderr, "listen error\n");

return;

len = sizeof(c_addr);

if((dataChannel.c_sock = accept(dataSock, (struct sockaddr *) &c_addr, &len)) ==

-1) {

fprintf(stderr, "accept error\n");

return;

make_ip( )

unsigned short np1, np2, np3;

char chaPort1[PORTLEN], chaPort2[PORTLEN];

224
const int MAX_NIC = 10;

const char *localip = "127.0.0.1";

struct ifconf ifc;

struct ifreq ifr[MAX_NIC];

int nIF;

int s;

int cmd = SIOCGIFCONF;

char ip[PORTLEN], chaIP[PORTLEN];

int i;

struct in_addr addr;

// make IP

ifc.ifc_len = sizeof(ifr);

ifc.ifc_ifcu.ifcu_req = ifr;

if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

fprintf(stderr, "socket open error");

if(ioctl(s, cmd, &ifc) < 0) {

fprintf(stderr, "IOCTL error");

close(s);

nIF = ifc.ifc_len / sizeof(struct ifreq);

strcpy(ip, localip);

225
for(i=0; i < nIF; i++) {

if(ifc.ifc_ifcu.ifcu_req[i].ifr_ifru.ifru_addr.sa_family != AF_INET) {

continue;

addr = ((struct sockaddr_in *)&ifc.ifc_ifcu.ifcu_req[i].ifr_ifru.ifru_addr)-

>sin_addr;

if(addr.s_addr == htonl(0x7f000001)) {

continue;

strcpy(ip, inet_ntoa(addr));

strcpy(dataChannel.ip, ip);

i = 0;

while(*(ip + i) != '\0') {

if(*(ip + i) == '.')

chaIP[i] = ',';

else

chaIP[i] = *(ip + i);

i++;

chaIP[i] = '\0';

strcpy(ip, chaIP);

226
strcpy(dataChannel.chaIp, ip);

// make port

np1 = np2 = np3 = 0;

srand(rand( ) % (time(NULL)));

np1 = (random( ) % 248) + 7;

np2 = random( ) % 255;

np3 = (np1 * 256) + np2;

dataChannel.port = np3;

sprintf(chaPort1, ",%d", np1);

sprintf(chaPort2, ",%d", np2);

strcat(chaPort1, chaPort2);

strcat(ip, chaPort1);

strcpy(dataChannel.chaPort, ip);

int getCode(char *message)

char chaCode[5];

strncpy(chaCode, message, 3);

strcat(chaCode, " ");

chaCode[4] = '\0';

227
return (atoi(chaCode));

</ 소스 >

228

You might also like