티스토리 뷰

문제?

 서버와 클라어인트 프로그램관 TCP 통신을 한다. 클라이언트는 편의상 fork를 사용하여 5개의 프로세스를 생성하고, 각 클라이언트는 랜덤값을 서버로 전송하고, 처리 결과값을 출력한다. 서버는 각 클라이언트마다 thread를 열고, 클라이언트에서 전송 받은 값을 전역변수인 result에 더한값을 저장하고, 클라이언트에 처리 결과를 넘겨준다. 저장한 값을 순차적으로 처리하기 위해서 mutex를 사용하여 처리한다.


thread에 대한 설명(위키백과)

  http://bit.thdev.net/KDIfzX

mutex(상호 배제)에 대한 설명(위키백과)

  http://bit.thdev.net/LO5vI1


결과 화면

 server 결과 화면


client 결과 화면


소스코드

server code

/*
  명령어 : gcc server.c -o server -pthread 
*/
#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>
#include <pthread.h>

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

void *thrfunc(void *arg); //쓰레드 시작 함수

int result = 0;
int cntNum = 0; //client count

//mutex
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

int main(int argc, char *argv[]) {
	struct sockaddr_in servaddr, cliaddr;
	int listen_sock, accp_sock[THREAD_NUM];
	int addrlen = sizeof(servaddr);
	int i, status ;
	pthread_t tid[THREAD_NUM];
	pid_t pid;

	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);
	}

	while(1) {
		listen(listen_sock, LISTENQ);

		puts("client wait....");

		accp_sock[cntNum] = accept(listen_sock, (struct sockaddr *)&cliaddr, &addrlen);
		if(accp_sock[cntNum] < 0) {
			perror("accept fail");
			exit(0);
		}

		if((status = pthread_create(&tid[cntNum], NULL, &thrfunc, (void *) &accp_sock[cntNum])) != 0) {
			printf("%d thread create error: %s\n", cntNum, strerror(status));
			exit(0);
		}

		//인자로 지정한 스레드 id가 종료하기를 기다립니다.
		pthread_join(tid[cntNum], NULL);
		cntNum++;
		if(cntNum == 5)
			cntNum = 0;
	}

	return 0;
}

void *thrfunc(void *arg) {
	int accp_sock = (int) *((int*) arg);
	int buf;

	read(accp_sock, &buf, 4);
	printf("client send value = %d\n", buf);
	pthread_mutex_lock(&lock);
	result += buf;
	printf("result = %d\n", result);
	pthread_mutex_unlock(&lock);
	write(accp_sock, &result, 4);

	close(accp_sock);
}

client code

/*
  명령어 : gcc client.c -o 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>
#include <time.h>

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

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]; //client fork
	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;
	int strlen = sizeof(servaddr);
	int sockfd, buf, cNum;//cNum 연결 번호

	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);
	}
	
	srand((unsigned)time(NULL));
	buf = rand() % 100 + 1; //rand 값 생성
	write(sockfd, &buf, 4); //server로 전송
	printf("cleint value : %d\n", buf);
	read(sockfd, &buf, 4); //server에서 받아 옴
	printf("Server sum result : %d\n", buf);
	close(sockfd);
}





댓글