Creative Code

Chapter1(서버,클라이언트 통신) 본문

TCP IP 소켓프로그래밍

Chapter1(서버,클라이언트 통신)

빛하루 2023. 10. 10. 08:42

※hello_server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

void error_handling(char *message);

int main(int argc, char *argv[])
{
	int serv_sock;          // 서버 소켓 디스크립터
	int clnt_sock;          // 클라이언트 소켓 디스크립터

	struct sockaddr_in serv_addr;  // 서버 주소 구조체
	struct sockaddr_in clnt_addr;  // 클라이언트 주소 구조체
	socklen_t clnt_addr_size;      // 클라이언트 주소 구조체의 크기

	char message[10];       // 메시지를 저장할 버퍼

	if (argc != 2) {
		printf("Usage : %s <port>\n", argv[0]);  // 프로그램 사용법 출력
		exit(1); // 프로그램 종료
	}

	// 서버 소켓 생성
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	if (serv_sock == -1)
		error_handling("socket() error");

	// 서버 주소 구조체 초기화
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET; // IPv4 형식 설정
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 모든 네트워크 인터페이스에서 접속 허용
	serv_addr.sin_port = htons(atoi(argv[1])); // 사용자가 입력한 포트 번호 설정

	// 소켓에 주소 정보 할당
	if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
		error_handling("bind() error");

	// 연결 대기 상태로 변경
	if (listen(serv_sock, 5) == -1)
		error_handling("listen() error");

	clnt_addr_size = sizeof(clnt_addr);

	// 클라이언트의 연결 요청을 수락
	clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
	if (clnt_sock == -1)
		error_handling("accept() error");

	// 표준 입력에서 메시지를 읽어서 클라이언트에게 전송
	read(0, message, 10);
	write(clnt_sock, message, sizeof(message));

	char *str_ptr;
	printf("clnt addr:%#x \n", clnt_addr.sin_addr);  // 클라이언트 주소 출력
	printf("clnt port:%#x \n", clnt_addr.sin_port);  // 클라이언트 포트 출력
	str_ptr = inet_ntoa(clnt_addr.sin_addr);  // 클라이언트 주소를 문자열로 변환
	printf("Dotted_Decimal notation1: %s\n", str_ptr);

	close(clnt_sock);
	close(serv_sock);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr); // 오류 메시지를 표준 오류 스트림에 출력
	fputc('\n', stderr);    // 개행 문자 출력
	exit(1);                // 프로그램 종료
}

※hello_client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

void error_handling(char *message);

int main(int argc, char* argv[])
{
	int sock; // 소켓 디스크립터를 저장할 변수
	struct sockaddr_in serv_addr; // 서버의 주소 정보를 저장할 구조체
	char message[30]; // 서버로부터 받을 메시지를 저장할 버퍼
	int str_len; // 읽은 메시지의 길이를 저장할 변수
	
	if(argc!=3){
		printf("Usage : %s <IP> <port>\n", argv[0]); // 프로그램 사용법 출력
		exit(1); // 프로그램 종료
	}
	
	sock = socket(PF_INET, SOCK_STREAM, 0); // 소켓 생성
	if(sock == -1)
		error_handling("socket() error"); // 소켓 생성 실패 시 오류 처리 함수 호출
	
	memset(&serv_addr, 0, sizeof(serv_addr)); // serv_addr 구조체 초기화
	serv_addr.sin_family = AF_INET; // 주소 체계 설정 (IPv4)
	serv_addr.sin_addr.s_addr = inet_addr(argv[1]); // 서버 IP 주소 설정
	serv_addr.sin_port = htons(atoi(argv[2])); // 서버 포트 번호 설정
		
	if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) 
		error_handling("connect() error!"); // 서버에 연결 실패 시 오류 처리 함수 호출
	
	str_len = read(sock, message, sizeof(message) - 1); // 서버로부터 데이터 읽기
	if(str_len == -1)
		error_handling("read() error!"); // 데이터 읽기 실패 시 오류 처리 함수 호출
	
	message[str_len] = '\0'; // 문자열 마지막에 널 문자 추가하여 문자열 종료
	printf("Message from server: %s \n", message); // 서버로부터 받은 메시지 출력  
	close(sock); // 소켓 닫기
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr); // 오류 메시지를 표준 오류 스트림에 출력
	fputc('\n', stderr); // 개행 문자 출력
	exit(1); // 프로그램 종료
}

이후 cmd창에서 ./hello_server 9190으로 포트번호까지 설정해 서버를 열어준뒤

또다른 cmd창에서 ./hello_client + IP주소 + 9190으로 서버에 접속할 수 있다. 

 

 

※low_open.c파일

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

void error_handling(char* message);

int main(void)
{
	int fd1,fd2;
	char buf[]="Let's go!\n";
	
	fd1=open("data.txt", O_CREAT /*필요시 파일 생성*/ |O_WRONLY/*쓰기용도*/ |O_TRUNC /*모든 내용 삭제*/); // fopen -> 파일을 열기위한 함수, open -> 파일,장치등을 열기위한 함수 
	if(fd1==-1)  // 파일을 열지 못했을 때
		error_handling("open() error!");
	printf("file descriptor: %d \n", fd1); // 파일 디스크립트 값 출력

	fd2=open("data2.txt", O_CREAT /*필요시 파일 생성*/ |O_WRONLY/*쓰기용도*/ |O_TRUNC /*모든 내용 삭제*/); // fopen -> 파일을 열기위한 함수, open -> 파일,장치등을 열기위한 함수 
	if(fd2==-1)  // 파일을 열지 못했을 때
		error_handling("open() error!");
	printf("file descriptor: %d \n", fd2); // 파일 디스크립트 값 출력

	if(write(fd1, buf, sizeof(buf))==-1)  //파일에 쓰기 실패했을 때
		error_handling("write() error!");

	close(fd1);
	if(write(fd2, buf, sizeof(buf))==-1)  //파일에 쓰기 실패했을 때
		error_handling("write() error!");

	close(fd2);
	return 0;
}

void error_handling(char* message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

/*
root@com:/home/swyoon/tcpip# gcc low_open.c -o lopen
root@com:/home/swyoon/tcpip# ./lopen
file descriptor: 3 
root@com:/home/swyoon/tcpip# cat data.txt
Let's go!
root@com:/home/swyoon/tcpip# 
*/

sudo chmod 777 data*로 파일의 권한을 모두 바꿔줘야한다.

 

※low_read.c파일

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

#define BUF_SIZE 100

void error_handling(char* message);

int main(void)
{
	int fd;                   // 파일 디스크립터를 저장할 변수
	char buf[BUF_SIZE];       // 데이터를 읽고 쓸 버퍼

	fd = open("data.txt", O_RDWR);  // "data.txt" 파일을 열고 파일 디스크립터를 반환
	if (fd == -1)
		error_handling("open() error!");  // 파일 열기 실패 시 오류 처리 함수 호출

	printf("file descriptor: %d\n", fd);  // 파일 디스크립터 출력

	// 표준 입력(0)에서 데이터를 읽어서 buf에 저장
	if (read(0, buf, sizeof(buf)) == -1)
		error_handling("read() error!");  // 읽기 실패 시 오류 처리 함수 호출

	// 파일 디스크립터(fd)를 통해 buf의 내용을 파일에 씀
	if (write(fd, buf, sizeof(buf)) == -1) {
		error_handling("write() error!");  // 쓰기 실패 시 오류 처리 함수 호출
	}

	printf("file data: %s", buf);  // 버퍼에 저장된 데이터 출력

	close(fd);  // 파일 디스크립터를 닫음
	return 0;
}

void error_handling(char* message)
{
	fputs(message, stderr);  // 오류 메시지를 표준 오류 스트림에 출력
	fputc('\n', stderr);     // 개행 문자 출력
	exit(1);                 // 프로그램 종료
}

※fd_seri.c파일

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>

int main(void)
{	
	int fd1, fd2, fd3;
	fd1=socket(PF_INET, SOCK_STREAM, 0);  // 소켓 생성
	fd2=open("test.dat", O_CREAT|O_WRONLY|O_TRUNC);	//파일 생성
	fd3=socket(PF_INET, SOCK_DGRAM, 0); // 소켓 생성
	
	printf("file descriptor 1: %d\n", fd1);
	printf("file descriptor 2: %d\n", fd2);
	printf("file descriptor 3: %d\n", fd3);
	
	close(fd1);
	close(fd2);
	close(fd3);
	return 0;
}