티스토리 뷰

728x90

문제 설명

 c언어 TCP 서버와 client 코드입니다. fork()를 이용해서 client는 1개의 부모와 5개의 자식으로 구성되며, 서버는 1개로 구성됩니다. Server로 fork()로 생성된 client 5개가 모두 서버로 접속하고, 접속 정보를 struct(구조체)에 저장하고, 구조체를 각 client로 전송 후 출력하는 코드입니다.


server 결과 화면 및 코드

 각 client 접속 로그를 보여주고 있습니다.


Server 코드

/*
	client 접속 정보를 담기위해서 client_info 구조체 생성
	Client 5개가 접속 될 때까지 대기 및 각 클라이언트간 메시지 전송
	접속이 완료되면 client_info를 각 클라이언트로 모두 전송 받음
	전송 받은 client 정보를 출력
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>

#define MAXLINE 1024 //buf 크기
#define LISTENQ 100 //Listen Q 설정
#define TOTALCL 5 //클라이언 동시 접속 수

//client 정보를 저장하기 위한 구조체 (접속 IP, port)
struct client_info {
	char clientAddr[32];
	int clientPort;
};

int main(int argc, char *argv[]) {
	struct sockaddr_in servaddr, cliaddr;
	struct client_info cliinfo[TOTALCL];
	int listen_sock, accp_sock[TOTALCL];
	int addrlen = sizeof(servaddr);
	int nbyte; //전송 받은 메시지 byte 저장
	char buf[MAXLINE];
	int conNum = 0;

	if(argc != 2) {
		printf("Use %s PortNumber\n", argv[0]);
		exit(0);
	}
	
	if((listen_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket Fail");
		exit(0);
	}

	memset(&servaddr, 0, sizeof(servaddr)); //0으로 초기화
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(atoi(argv[1]));

	//bind 호출
	if(bind(listen_sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
		perror("bind Fail");
		exit(0);
	}
	
	//소켓을 수동 대기모드로 세팅
	listen(listen_sock, LISTENQ);

	//interative 에코 서비스 수행
	while(conNum < 5) {
		puts("서버가 연결 요청을 대기");		

		accp_sock[conNum] = accept(listen_sock, (struct sockaddr *)&cliaddr, &addrlen);
		if(accp_sock[conNum] < 0) {
			perror("accept fail");
			exit(0);
		}
		
		strcpy(cliinfo[conNum].clientAddr, inet_ntoa(cliaddr.sin_addr));
		cliinfo[conNum].clientPort = ntohs(cliaddr.sin_port);
		printf("Client 연결 됨 IP %s, Port %d\n", cliinfo[conNum].clientAddr, cliinfo[conNum].clientPort);

		//접속 성공 메시지
		if((nbyte = read(accp_sock[conNum], buf, MAXLINE)) < 0) {
			perror("read fail");
			exit(0);
		}
		buf[nbyte] = 0;
		if(!strncmp(buf, "Connect Success", 15)) {
			printf("client message : %s\n", buf);
		}

		conNum++; //접속자 수 증가
	}

	puts("모든 클라이언트에 접속 정보 전송");
	conNum = 0;
	while(1) {
		buf[0] = '\0';
		send(accp_sock[conNum], &cliinfo, sizeof(struct client_info) * 5, 0);
		
		if((nbyte = read(accp_sock[conNum], buf, MAXLINE)) < 0) {
			perror("set read fail");
			exit(0);
		}
		buf[nbyte] = 0;
		printf("%s\n", buf);
		if(!strncmp(buf, "GetOK", 5)) {
			conNum++;
			if(conNum == 5)
				break;
		}
	}

	close(listen_sock);
	
	return 0;
}

Client 실행 및 로그

 Client 에서 Server로 접속하고, 모든 client 접속 정보를 출력한 결과화면 입니다.

 5개의 자식 프로세스가 동시에 보이고 있기 때문에 pid로 구분하여 출력했습니다.


client 접속 코드

/*
	fork()를 이용하여 1개의 부모와 5개의 자식 프로세스를 생성
	생성된 자식 프로세스는 각각 서버와 connect
	connect 된 후 서버에 전송해주는 5개의 자식프로세스
	접속 정보를 객체로 받아 출력
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>

#define MAXLINE 1024 //buf 크기
#define TOTALFORK 5 //클라이언트 수

struct client_info {
	char clientAddr[32];
	int clientPort;
};

void createClient(char *port, char *serverIP);
int main(int argc, char *argv[]) {
	if(argc != 3) {
		printf("Use %s ip_addr port\n", argv[0]);
		exit(0);
	}

	pid_t pids[TOTALFORK];
	int runProcess = 0;
	
	while(runProcess < TOTALFORK) {
		sleep(1);
		pids[runProcess] = fork();

		if(pids[runProcess] < 0) {
			return -1;
		}
		
		if(pids[runProcess] == 0) {
			createClient(argv[2], argv[1]);
			exit(0);
		} else { //부모 프로세스
			printf("parent %ld, child %ld\n", (long)getpid(), (long)pids[runProcess]);
		}
		runProcess++;
	}
	return 0;
}

void createClient(char *port, char *serverIP) {
	struct sockaddr_in servaddr;
	struct client_info *cliinfo;
	int strlen = sizeof(servaddr);
	cliinfo = malloc(TOTALFORK);
	int sockfd, nbyte, cNum;//cNum 연결 번호
	char buf[MAXLINE];

	if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket fail");
		exit(0);
	}

	memset(&servaddr, 0, strlen);
	servaddr.sin_family = AF_INET;
	inet_pton(AF_INET, serverIP, &servaddr.sin_addr);
	servaddr.sin_port = htons(atoi(port));

	if(connect(sockfd, (struct sockaddr *)&servaddr, strlen) < 0) {
		perror("connect fail");
		exit(0);
	}
	
	//접속 성공 메시지
	strcpy(buf, "Connect Success");
	write(sockfd, buf, sizeof(buf));

	//모든 client 접속 정보 받아 옴
	recv(sockfd, cliinfo, sizeof(struct client_info) * 5, 0);

	strcpy(buf, "GetOK");
	write(sockfd, buf, sizeof(buf));
	
	printf("pid : %ld, 받은 정보 출력\n", (long)getpid());
	int i;
	for(i = 0; i < TOTALFORK; i++) {
		printf("pid:%ld, ip:%s port:%d\n", (long)getpid(), cliinfo[i].clientAddr, cliinfo[i].clientPort);
	}
	
	close(sockfd);
}





댓글