반응형

TCP 패킷의 특징은 데이터에 대해서 1. 연결지향성 2. 신뢰성 보장이 있습니다. 

무조건 데이터를 상대방에게 전송합니다. 하지만 받는 쪽에서 전체 데이터를 못받을 수 있다는 문제점이 있습니다.

 

아래는 대표적인 client.cpp 코드입니다.

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

 

네트워크 상태에 따라서 패킷이 찢어져서 들어오게 된다면 어떻게 될까요

정답은 짤린 패킷이 여러번에 걸쳐서 입력되는 형태 입니다. 

 

이러한 문제를 해결하기 위해서 while루프, length, offset을 사용해야합니다.

아래 처럼 offset과 length를 통해서 받은 만큼 표시를 해주며, 원하는 크기까지 받도록 무한 루프를 구성해야 합니다.

 int length = sizeof(Data) + strlen(name_msg);  //
 int offset = 0;
        while(1){
            int n = send(sock, data + offset, length, 0);

            if(n == -1){
                if(errno == EINTR) // signal interrupted
                    continue;
                else if(errno == EBADF)
                    cout<< "reject in network"<<endl;
                else if(errno == ENOTSOCK)
                    cout<< "sock err"<<endl;

                return (void*) - 1;
             }
            offset += n;
            length -= n;
            if(length == 0)
                break;
            
        }

 

그렇기 때문에 만약 서버라면 클라이언트별로 버퍼를 구성해주어야 합니다. 

 

 

아래 링크도 참고하세요.

stackoverflow.com/questions/43759231/sending-and-receiving-all-data-c-sockets

 

Sending and receiving all data (C++ sockets)

Help me please to find out what is wrong in client-server communication... The client sends to server jpeg frames from camera 25 times per second using this function: int SendAll(SOCKET &

stackoverflow.com

근데 이때, 구조체가 가변길이이고, 패킷 헤더에서 패킷의 길이를 전달해주는 구조라면 구현이 더욱 복잡해집니다. 

실제 이렇게 세세한 부분까지는 자료도 거의 없어서 직접 구현을 해야한다는 어려움이 있습니다. 

반응형

+ Recent posts