echo_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 void error_handling(char *message); int main(int argc, char *argv[]) { int serv_sock, clnt_sock; char message[BUF_SIZE]; int str_len, i;
struct sockaddr_in serv_adr; struct sockaddr_in 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++) { clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz); if(clnt_sock==-1) error_handling("accept() error"); else printf("Connected client %d \n", i+1);
while((str_len=read(clnt_sock, message, BUF_SIZE))!=0) write(clnt_sock, message, str_len); close(clnt_sock); } close(serv_sock); return 0; } void error_handling(char *message) { fputs(message, stderr); fputc('\n', stderr); exit(1); } |
echo_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 void error_handling(char *message); int main(int argc, char *argv[]) { int sock; char message[BUF_SIZE]; int str_len; 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...........");
while(1) { fputs("Input message(Q to quit): ", stdout); fgets(message, BUF_SIZE, stdin);
if(!strcmp(message,"q\n") || !strcmp(message,"Q\n")) break; write(sock, message, strlen(message)); str_len=read(sock, message, BUF_SIZE-1); message[str_len]=0; printf("Message from server: %s", message); }
close(sock); return 0; } void error_handling(char *message) { fputs(message, stderr); fputc('\n', stderr); exit(1); } |
에코 클라이언트의 문제점
- 제대로 동작은 하나 문제의 발생 소지가 있는 TCP 에코 클라이언트의 코드
write(sock. message, strlen(message)); str_len = read(sock, message, BUF_SIZE=1); message[str_len] = 0; printf("Message from server: %s", message); |
TCP의 데이터 송수신에는 경계가 존재하지 않는다! 그런데 위의 코드는 다음 사항을 가정하고 있다.
"한 번의 read 함수 호출로 앞서 전송된 문자열 전체를 읽어 들일 수 있다."
그러나 이는 잘못된 가정이다. TCP에는 데이터의 경계가 존재하지 않기 때문에 서버가 전송한 문자열의 일부만 읽혀질 수도 있다.
'이전것 > 개발' 카테고리의 다른 글
해피해킹 딥스위치 설정 (0) | 2016.12.05 |
---|---|
Vi/Vim 단축키 모음 (0) | 2016.12.02 |
vim 단축키 일람 (0) | 2016.12.02 |
리눅스 - 파일 폴더 권한 바꾸기 (0) | 2016.12.02 |
4.2. TCP기반 서버, 클라이언트의 구현 (0) | 2016.12.01 |