Demo entry 6628942

1

   

Submitted by anonymous on Jul 05, 2017 at 22:24
Language: C. Code size: 4.9 kB.

/*헤더파일 선언*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#define BUFSIZE 1024 //메시지를 저장할 크기를 정의

void error_handling(char *message); //error_handling 함수 선언

int main(int argc, char **argv) { //port 정보를 받는다
	int serv_sock; //서버 디스크립터를 저장할 변수 선언
	int clnt_sock; //클라이언트 디스크립터를 저장할 변수 선언
	char message[BUFSIZE]; //메시지를 저장할 배열 선언
	int str_len; //수신받은 데이터의 크기를 저장할 변수 선언

	struct sockaddr_in serv_addr; //서버의 주소정보를 저장할 구조체 변수
	struct sockaddr_in clnt_addr; //클라이언트의 주소정보를 저장할 구조체 변수
	int clnt_addr_size; //클라이언트 정보 구조체의 크기를 저장할 변수

	/*하단 if문 설명 : 첫번째 argv[0]에는 실행을 위한 './파일명'이,
	                   argv[1]에는 port번호가 들어갈 것이므로
	                   argc == 2일 경우 올바른 정보를 입력했다고 할 수 있다*/

	if(argc != 2) { //port정보가 올바르지 않다면, if문 실행
		printf("Usage :%s <port>\n", argv[0]); //error 출력
		exit(1); //프로그램 강제 종료
	}

	/*if문을 확인하기 위해 실행'./server'만 입력해보자?

	하단의 함수소켓 설명 : 소켓 생성 실패 시 '-1' 반환
			       소켓 생성 성공 시 '-1' 이외의 수 반환

	if(serv_sock != -1)로 바꾼다면 에러 메시지가 출력됨*/

	serv_sock = socket(PF_INET, SOCK_STREAM, 0); //**소켓 생성**

	/*PF_INET : IPv4, 프로토콜 체계를 표현할 때 사용*/

	if(serv_sock == -1) //소켓 생성 실패 시, if문 실행
		error_handling("socket() error"); //에러 입력받을 시 >> 함수 이동
	//memest(&serv_addr, 0, sizeof(serv_addr)); //**나는 웨 안되는 걸까**
	serv_addr.sin_family = AF_INET; //프로토콜 체계 설정

	/*상단 설명 : serv_addr의 sin_family멤버에 AF_INET를 대입함
		      AF_INET : IPv4, 주소 체계를 표현할 때 사용*/

	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	/*상단 설명 : serv_addr의 sin_addr안에 s_ddr에는
		      hton1(INADDR_ANY)대입
	htonl(INADDR_ANY) : htonl함수이다,
			    Network에서는 Big-Ending방식을 사용하기 때문에,
			    System과의 방식을 맞춰주기 위한 함수 
			    포트번호를 Host byte 에서 Network byte 순서로!
	INADDR_ANY : 서버의 IP주소를 자동으로 찾아서 대입해주는 함수이다*/

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

	/*serv_addr의 sin_port에 htons(atoi(argv[1]))을 대입
	  1. argv[1] == 내가 앞에서 설정한 포트번호이다(ex) argv[1] == 7899)
	  2. atoi(포트번호) : atoi()은 <stdlib.h> 헤더파일에 선언되어있다
			      문자열을 정수형으로 변환한다
			      (ex) atoi(7899) : 문자열 형태의 7899를
				   		정수형 형태의 7899로 변환
	  3. **htons(정수형) : IP주소를 host 바이트 순서에서
			       Network 바이트 순서로** */

	if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
		error_handling("bind() error");

	/*소켓에 주소 할당
	  상단 설명 : 
	  1. sizeof(serv_addr) : 구조체의 크기
	  2. (struct sockaddr*)&serv_addr :
	     serv_addr의 주소값을 sockaddr 구조체 포인터 자료형으로 강제 형변환
	     Q1. 하는 이유는?
	  3. bind(소켓 디스크립터, 로컬 주소, 로컬 주소 구조체 크기)
	     bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) :
	     bind() - 소켓번호와 소켓주소의 결합을 위한 함수
	     	      클라이언트가 서버 프로그램의 특정 소켓으로 접속하려면
		      서버는 자신의 소켓번호와 클라이언트가 알고있는
		      자신의 IP주소, 포트번호를 미리 연결해 두어야 한다
		      bind()는 성공 시 '0', 실패 시 '-1'을 반환한다 
	      A1. bind()는 sockaddr 포인터 자료형을 요구하기 때문에*/

	if(listen(serv_sock, 5) == -1)
		error_handling("listen() error");

	/*상단 설명 : listen()
	  listen(클라이언트로부터 연결 요청을 받아들이기 위한 소켓 파일
	  디스크립터, 연결요쳥 대기 큐(연결 요청을 대기 시킬 수 있는
	  일종의 대기실)의 크기에 대한 설정)
	  listen 함수 호출을 성공하게 되면, 여러 클라이언트들이 요청을
	  해 올것이고, 모든 연결 요청은 서버가 미리 만들어 놓은
	  대기실로 들어가 순서대로 연결요청이 수락될 때 까지 기다려야 함
	  listen()은 성공 시 '0', 실패 시 '-1'을 반환한다
	
	  listen()을 호출하면 서버 소켓 상태는 CLOSE에서 LISTEN 상태로
	  변경되고, 연결을 요청한 클라이언트 소켓은 SYN_RCVD 상태에서
	  3-way-handshaking을 완료하고 ESTABLISHED상태가 된다*/

	clnt_addr_size = sizeof(clnt_addr); //client 주소 정보 구조체의 크기 저장
	clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
	/*연결 요청 수락
	  
	  1. &clnt_addr_size : client 주소 정보 구조체의 주소값
	  2. (struct sockaddr*)&clnt_addr : 
	     clnt_addr의 주소값을 sockaddr 구조체 포인터 자료형으로 강제 형변환
	  3. accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size) : 
	     accept() : 아직 처리되지 않은 연결들이 대기하고 있는 큐에서
	                제일 처음 연결된 연결을 가져와 새로운 연결된 소켓을
	                만든다, 성공 시 '새로 생긴 파일의 디스크립터'를 리턴,
			실패 시 '-1'을 리턴함*/ 

	if(clnt_sock == -1) //accept()의 리턴값이 -1이면..
		error_handling("accept() error"); //error 구문을 띄운다

	while((str_len = read(clnt_sock, message, BUFSIZE)) != 0) {
		write(clnt_sock, message, str_len);
		write(1, message, str_len);
	}
	
	/*상단 설명 :
	  1. while(조건) : 조건이 참일 때 반복한다, 메시지를 수신받고
	     길이 저장, EOF를 만나면 반복문 탈출!
	  2. str_len : 수신받은 데이터의 크기를 저장할 변수
	  3. read(파일 디스크립터, 읽은 데이터를 저장할 버퍼,
	     읽을 데이터의 최대의 길이(= 1024) : 
  	     읽은 값의 길이를 나타낸다, 성공 시 '수신한 바이트 수'를 리턴하며,
	     실패 시에는 '-1'을 리턴한다
	     (= 수신한 메시지의 크기만큼 데이터 전송)
	  4. 읽은 값의 길이가 수신받은 데이터의 크기이며 이것이 0이 아닐 경우 :
	     write(파일 디스크립터, 전송할 버퍼, 전송할 데이터 길이) :
	     쓴 값의 길이를 나타낸다, 쓰기에 성공할 시
	     '쓰기에 성공한 길이'를 반환하고,
	     오류가 발생하면 '-1'을 반환한다
	     ** (= 메시지를 server에 출력 (표준 출력)** */

	close(clnt_sock); //클라이언트 소켓 종료

	return 0; //프로그램 정상 종료
}

void error_handling(char *message) { //에러 메시지를 매개변수로 받아 실행되었다
	fputs(message,stderr);  //오류 메시지 출력
	fputc('\n', stderr); //개행 출력
	exit(1); //함수 강종
}

This snippet took 0.00 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).