반응형

pthread를 사용하여 수신하는 문자열을 출력해주도록 작성된 소켓 서버 / 클라이언트 예제입니다. 

 

원본 코드 출처는 아래 깃허브 저장소입니다.  

https://github.com/shineyr/Socket

 

 

실행 결과는 다음과 같습니다. 

 

서버를 실행한 후, 클라이언트를 실행하여 서버에 접속합니다.

클라이언트에서 hi를 입력하여 전송하고 서버에선 해당 문자열을 출력합니다.

서버에서 hello를 입력하여 전송하고 클라이언트에선 해당 문자열을 출력합니다. 

서버에서 Ctrl + C 를 눌러 갑자기 접속을 끊어버리면 클라이언트도 종료합니다.

반대로 클라이언트에서 Ctrl + C를 눌러 갑자기 접속을 끊어버리면 서버도 종료합니다.  

 

 

서버측 로그

$ ./server
server: got connection from 127.0.0.1

Client: hi

hello
^C

 

클라이언트측 로그

$ ./client 127.0.0.1
hi

Server: hello

Server is closed.

 

서버 코드

// https://github.com/shineyr/Socket/blob/master/pthread_socket/server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <pthread.h>

const int MAX_LINE = 2048;
const int PORT = 6001;
const int BACKLOG = 10;
const int LISTENQ = 6666;
const int MAX_CONNECT = 20;


// 클라이언트로부터 메시지 수신
void *recv_message(void *fd)
{
	int sockfd = *(int *)fd;
	while(1)
	{
		char buf[MAX_LINE];
		memset(buf , 0 , MAX_LINE);
		int n;
		if((n = recv(sockfd , buf , MAX_LINE , 0)) == -1)
		{
			perror("recv error.\n");
			exit(1);
		}
		buf[n] = '\0';

        // 클라이언트가 갑자기 접속을 끊은 경우 처리 
        if (n==0)
        {
			printf("Client closed.\n");
			close(sockfd);
			exit(1);
        }

		// byebye. 문자열을 받으면 종료
		if(strcmp(buf , "byebye.") == 0)
		{
			printf("Client closed.\n");
			close(sockfd);
			exit(1);
		}

		printf("\nClient: %s\n", buf);
	}
}

int main()
{
	int listenfd , connfd;
	socklen_t clilen;
	pthread_t recv_tid , send_tid;

	struct sockaddr_in servaddr , cliaddr;
	
	if((listenfd = socket(AF_INET , SOCK_STREAM , 0)) == -1)
	{
		perror("socket error.\n");
		exit(1);
	}


	bzero(&servaddr , sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(PORT);


    // bind 오류 해결. 사용했던 ip라고 뜨는 에러. 
    int val = 1;    
    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof val) < 0) {
        perror("setsockopt");
        close(listenfd);
	    return -1;
    }

	if(bind(listenfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0)
	{
		perror("bind error.\n");
		exit(1);
	}

	if(listen(listenfd , LISTENQ) < 0)
	{
		perror("listen error.\n");
		exit(1);
	}

	clilen = sizeof(cliaddr);
	if((connfd = accept(listenfd , (struct sockaddr *)&cliaddr , &clilen)) < 0)
	{
		perror("accept error.\n");
		exit(1);
	}

	printf("server: got connection from %s\n", inet_ntoa(cliaddr.sin_addr));

	// 메시지 수신하는 스레드 생성
	if(pthread_create(&recv_tid , NULL , recv_message, &connfd) == -1)
	{
		perror("pthread create error.\n");
		exit(1);
	}

	//서버가 입력한 메시지 전송
	char msg[MAX_LINE];
	memset(msg , 0 , MAX_LINE);
	while(fgets(msg , MAX_LINE , stdin) != NULL)	
	{	
		if(strcmp(msg , "exit\n") == 0)
		{
			printf("byebye.\n");
			memset(msg , 0 , MAX_LINE);
			strcpy(msg , "byebye.");
			send(connfd , msg , strlen(msg) , 0);
			close(connfd);
			exit(0);
		}

		if(send(connfd , msg , strlen(msg) , 0) == -1)
		{
			perror("send error.\n");
			exit(1);
		}		
	}
}

 

 

클라이언트 코드

// https://github.com/shineyr/Socket/blob/master/pthread_socket/client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <pthread.h>

const int MAX_LINE = 2048;
const int PORT = 6001;


// 서버로부터 메시지 수신
void *recv_message(void *fd)
{
	int sockfd = *(int *)fd;
	while(1)
	{
		char buf[MAX_LINE];
		memset(buf , 0 , MAX_LINE);
		int n;
		if((n = recv(sockfd , buf , MAX_LINE , 0)) == -1)
		{
			perror("recv error.\n");
			exit(1);
		}
		buf[n] = '\0';

        // 서버가 갑자기 접속을 끊은 경우 처리
		if (n == 0)
		{
			printf("Server is closed.\n");
			close(sockfd);
			exit(0);
		}
		
		// byebye. 문자열을 받으면 종료
		if(strcmp(buf , "byebye.") == 0)
		{
			printf("Server is closed.\n");
			close(sockfd);
			exit(0);
		}

		printf("\nServer: %s\n", buf);
	}
}


int main(int argc , char **argv)
{
    int sockfd;
	pthread_t recv_tid , send_tid;
    struct sockaddr_in servaddr;


     // 실행할때 접속할 서버의 아이피를 요구
    if(argc != 2)
    {
        perror("usage:tcpcli <IPaddress>");
        exit(1);
    }

    
    if((sockfd = socket(AF_INET , SOCK_STREAM , 0)) == -1)
    {
        perror("socket error");
        exit(1);
    }


    bzero(&servaddr , sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    if(inet_pton(AF_INET , argv[1] , &servaddr.sin_addr) < 0)
    {
        printf("inet_pton error for %s\n",argv[1]);
        exit(1);
    }


    if( connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0)
    {
        perror("connect error");
        exit(1);
    }


	// 메시지 수신하는 스레드 생성
	if(pthread_create(&recv_tid , NULL , recv_message, &sockfd) == -1)
	{
		perror("pthread create error.\n");
		exit(1);
	}	


    // 클라이언트가 입력한 메시지 전송
	char msg[MAX_LINE];
	memset(msg , 0 , MAX_LINE);
	while(fgets(msg , MAX_LINE , stdin) != NULL)	
	{
		if(strcmp(msg , "exit\n") == 0)
		{
			printf("byebye.\n");
			memset(msg , 0 , MAX_LINE);
			strcpy(msg , "byebye.");
			send(sockfd , msg , strlen(msg) , 0);
			close(sockfd);
			exit(0);
		}

		if(send(sockfd , msg , strlen(msg) , 0) == -1)
		{
			perror("send error.\n");
			exit(1);
		}
		
	}
}

 

반응형

해본 것을 문서화하여 기록합니다.


포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
질문을 남겨주면 가능한 빨리 답변드립니다.


제가 쓴 책도 한번 검토해보세요 ^^

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기

댓글을 달아 주세요

">