에코클라이언트의 문제점 확인하기 

에코 서버의 코드

while((str_len=read(clnt_sock, message, BUF_SIZE)) != 0)

    write(clnt_sock, message, str_len); 

서버는 데이터경계를 구분하지 않고 수신된 데이터를 그대로 전송할 의무만 갖는다. TCP가 본디 데이터의 경계가 없는 프로토콜

이므로, 두 번의 write 함수 호출을 통해서 데이터를 전송하건, 세 번의 write 함수 호출을 통해서 데이터를 전송하건, 문제 되지 않는다.


에코 클라이언트의 코드

write(sock, message, strlen(message));

str_len = read(sock, message, BUF_SIZE - 1); 


반면, 클라이언트는 문장 단위로 데이터를 송수신(BUF_SIZE-1) 하기 때문에, 데이터의 경계를 구분해야한다. 때문에 이와 같은 데이터 송수신 방식은 문제가 된다. TCP의 read & write 함수 호출은 데이터의 경계를 구분하지 않기 때문이다.



에코 클라이언트의 해결책!

str_len = write(sock, message, strlen(message));

recv_len = 0;

while(recv_len(str_len) {

    recv_cnt = read(sock, &message[recv_len], BUF_SIZE-1);

    if(recv_cnt == -1)

        error_handling("read() error!");

    recv_len += recv_cnt;

}

message[recv_len] = 0;

printf("Message from server : %s", message); 

write 함수호출을 통해서 전송한 데이터의 길이 만큼 읽어 들이기 위한 반복문의 삽입이 필요하다. 이것이 TCP를 기반으로 데이터를 구분지어 읽어 들이는데 부가적으로 필요한 구분이다.



op_server.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/socket.h>


#define BUF_SIZE 1024

#define OPSZ 4

void error_handling(char *message);

int calculate(int opnum, int opnds[], char oprator);


int main(int argc, char *argv[])

{

int serv_sock, clnt_sock;

char opinfo[BUF_SIZE];

int result, opnd_cnt, i;

int recv_cnt, recv_len;

struct sockaddr_in serv_adr, clnt_adr;

socklen_t clnt_adr_sz;

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_adr, 0, sizeof(serv_adr));

serv_adr.sin_family=AF_INET;

serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);

serv_adr.sin_port=htons(atoi(argv[1]));


if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)

error_handling("bind() error");

if(listen(serv_sock, 5)==-1)

error_handling("listen() error");

clnt_adr_sz=sizeof(clnt_adr);


for(i=0; i<5; i++)

{

opnd_cnt=0;

clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);

read(clnt_sock, &opnd_cnt, 1);

recv_len=0;

while((opnd_cnt*OPSZ+1)>recv_len)

{

recv_cnt=read(clnt_sock, &opinfo[recv_len], BUF_SIZE-1);

recv_len+=recv_cnt;

}

result=calculate(opnd_cnt, (int*)opinfo, opinfo[recv_len-1]);

write(clnt_sock, (char*)&result, sizeof(result));

close(clnt_sock);

}

close(serv_sock);

return 0;

}


int calculate(int opnum, int opnds[], char op)

{

int result=opnds[0], i;

switch(op)

{

case '+':

for(i=1; i<opnum; i++) result+=opnds[i];

break;

case '-':

for(i=1; i<opnum; i++) result-=opnds[i];

break;

case '*':

for(i=1; i<opnum; i++) result*=opnds[i];

break;

}

return result;

}


void error_handling(char *message)

{

fputs(message, stderr);

fputc('\n', stderr);

exit(1);



op_client.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/socket.h>


#define BUF_SIZE 1024

#define RLT_SIZE 4

#define OPSZ 4

void error_handling(char *message);


int main(int argc, char *argv[])

{

int sock;

char opmsg[BUF_SIZE];

int result, opnd_cnt, i;

struct sockaddr_in serv_adr;

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_adr, 0, sizeof(serv_adr));

serv_adr.sin_family=AF_INET;

serv_adr.sin_addr.s_addr=inet_addr(argv[1]);

serv_adr.sin_port=htons(atoi(argv[2]));

if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)

error_handling("connect() error!");

else

puts("Connected...........");


fputs("Operand count: ", stdout);

scanf("%d", &opnd_cnt);

opmsg[0]=(char)opnd_cnt;

for(i=0; i<opnd_cnt; i++)

{

printf("Operand %d: ", i+1);

scanf("%d", (int*)&opmsg[i*OPSZ+1]);

}

fgetc(stdin);

fputs("Operator: ", stdout);

scanf("%c", &opmsg[opnd_cnt*OPSZ+1]);

write(sock, opmsg, opnd_cnt*OPSZ+2);

read(sock, &result, RLT_SIZE);

printf("Operation result: %d \n", result);

close(sock);

return 0;

}


void error_handling(char *message)

{

fputs(message, stderr);

fputc('\n', stderr);

exit(1);

}




블로그 이미지

잉비니

,