리눅스 소켓통신에서 바이너리 데이터를 어떻게 보내야 될까요??
글쓴이: 익명 사용자 / 작성시간: 목, 2019/05/09 - 12:12오전
리눅스에서 실행파일이나 이미지파일의 데이터를 읽어서 보내려고 합니다.
두 개 다 바이너리 파일인데 write를 써서 보내야하는 것 까진 알고 있는데
어떻게 보내야 될지를 잘 모르겠습니다.
FILE *ftr1 = fopen("4323424.JPG","rb");
FILE *ftr2 = fopen("43234241.JPG","wb");
char buf[100000];
int read;
while(1)
{
read = fread((void *)buf,1,100000,ftr1);
if(read<100000)
{
if(feof(ftr1) != 0)
{
fwrite((void *)buf,1,read,ftr2);
break;
}
}
fwrite((void *)buf,1,100000,ftr2);
}
remove("43234241.JPG");
fclose(ftr1);
fclose(ftr2);
이 코드로 fwrite를 사용해서 void형 인자로 open형으로 이미지를 덮어씌우면서 buf형 데이터로 이미지를 복사했고 복사한 이미지를 삭제하고 buf데이터만 남긴 상태에서 client쪽으로 write(client,(char)buf,sizeof(buf))와같은 형식으로 데이터를 전송했으나 데이터는 잘 전송이 되나 이걸 이미지로 읽지를 못하네요. 제가 어떤 부분에서 실수를 한 건가요??
Forums:
전형적인 client-server 소켓 통신 방식으로
전형적인 client-server 소켓 통신 방식으로 해결될 수 있을 것으로 보이는데, 소켓 통신에서 받은 데이터를 fwrite()로 저장하면 될 것 같습니다.
Quote:데이터는 잘 전송이 되나 이걸 이미지로
보통 그런 걸 보고 "잘 전송이 안 됐다"고 합니다.
간단한 가이드라인을 드리지요.
1. 원본 파일과 전송된 파일의 크기가 같은가요?
전송이 잘 됐다면 당연히 같아야 하지요. 하지만 의외로 뭔가 잘못됐다면 여기서 잘못될 가능성이 가장 높습니다. 그러니 가장 먼저 체크해야지요.
2. 원본 파일과 전송된 파일이 실제로 동일한 내용을 가지고 있나요?
파일이 크다면 이걸 직접 확인하기는 어렵지요. 가장 쉬운 방법은 diff 명령어를 쓰는 겁니다.
diff (원본) (사본)
아무 출력도 안 나오면 같은 파일인 겁니다. 다른 부분이 있다면, 텍스트 파일이라면 어디가 다른지 알려주고, 바이나리 파일이라면 "Binary files (원본) and (사본) differ" 라고 나오지요.
네트워크 프로그래밍 중이어서 원본과 사본이 다른 컴퓨터에 있다면 diff를 직접 쓸 수가 없지요. 그 땐 sha512sum 같은 명령어로 해시를 해서 똑같은 결과가 나오는지 확인해 보면 됩니다.
아닌 게 아니라, 클라이언트에게
write(client,(char)buf,sizeof(buf))
으로 데이터를 줬다면,(1) 보내야 할 데이터가 sizeof(buf)보다 작아도, 서버는 무조건 sizeof(buf)만큼 보내겠군요
(2) 클라이언트는 (sizeof(buf) 말고) 실제 데이터의 크기를 어떻게 알 수 있죠?
이런 종류의 실수 때문에 위 1에 걸리는 잘못된 파일 전송이 자주 일어나는 겁니다.
말씀해주신대로
말씀해주신대로 diff명령어를 써서 두 파일이 다르다는 것을 확인했고,
이를 fseek로 size를 읽어와서 전체 size를 확보했습니다.
이 전체 size의 크기까지 이미지를 받아서 이미지를 복사했는데
복사한 이미지가 같다는 것을 확인했습니다.
이 정보를 write(client_fd,buf,size)로 정확한 file size만큼 보냈는데, 이것을 소켓 클라이언트가 이미지로 인식을 하지 못하고 있습니다. 이미지 전송 형식으로 헤더에 content-Type을 image로 작성했는데, 이미지로 전송이 안되고 텍스트 타입으로 전송이 되고 있네요.
sprintf를 사용해서 response_body에 파일의 내용을 복사했고,
이 복사된 내용을 나중에 write로 클라이언트에 보내는 방식을 취했습니다.
누가 이미지로 인식해요?
누가 이미지로 인식해요?
"소켓"이 "TCP 소켓"을 의미하는 것이라면, TCP 프로토콜은 전송되는 데이터가 이미지인지 아닌지 전혀 신경쓰지 않습니다. 그걸 신경쓰는 건 애플리케이션 레벨에서 해 줘야 할 일이지요.
content-Type 운운하는 것을 보니 http 프로토콜인가 보죠? 서버와 클라이언트를 모두 직접 짜고 있나요? http request/response 헤더를 모두 올려 보시기 바랍니다. 어딘가 문제가 있겠죠.
어떤 부분이 문제인 건가요 ㅠ
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include"ls.c"
#define URL_LEN 256
#define BUFSIZE 1024
#define PORTNO 40206
int main(int argc, char **argv){
char buff[100],buff1[100];
getcwd(buff,100);
getcwd(buff1,100);
struct sockaddr_in server_addr, client_addr;
int socket_fd, client_fd;
int len,len_out;
int opt =1;
if((socket_fd = socket(PF_INET, SOCK_STREAM, 0)) <0) {
printf("Server : can't open stream socket\n");
return 0;
}
setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORTNO);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(socket_fd, (struct sockaddr *)&server_addr,sizeof(server_addr)) <0){
printf("Server : can't bind local address\n");
return 0;
}
listen(socket_fd ,5);
/// 소켓 open
while(1)
{
struct in_addr inet_client_address;
char buf[BUFSIZE] = {0,};
char tmp[BUFSIZE] = {0,};
char url[1024] = {0,};
char response_header[BUFSIZE] = {0,};
char response_message[BUFSIZE] = {0,};
char response_body[BUFSIZE] = {0,};
char method[20] = {0,};
char *tok = NULL;
memset(response_message,0,BUFSIZE);
len = sizeof(client_addr);
client_fd = accept(socket_fd, (struct sockaddr*)&client_addr, &len); // 소켓 연결
if(client_fd <0){
printf("Server:accept failed\n");
return 0;
}
inet_client_address.s_addr = client_addr.sin_addr.s_addr;
printf("%s %d client was connected\n", inet_ntoa(inet_client_address), client_addr.sin_port);
read(client_fd,buf,BUFSIZE);
strcpy(tmp,buf);
printf("Request from %s %d\n", inet_ntoa(inet_client_address), client_addr.sin_port);
puts(buf);
tok = strtok(tmp," ");
strcpy(method, tok);
if(strcmp(method,"GET") == 0)
{
tok = strtok(NULL, " ");
strcpy(url,tok);
} /// url을 얻는다
int size;
FILE *ftr1 = fopen("a.JPG","rb");
FILE *ftr2 = fopen("b.JPG","w");
fseek(ftr1, 0, SEEK_END); // 파일 포인터를 파일의 끝으로 이동시킴
size = ftell(ftr1); // 파일 포인터의 현재 위치를 얻음
fseek(ftr1, 0, SEEK_SET);
char buf[100000];
int read;
while(1)
{
read = fread((void *)buf,1,size,ftr1);
if(read<100000)
{
if(feof(ftr1) != 0)
{
fwrite((void *)buf,1,read,ftr2);
break;
}
}
fwrite((void *)buf,1,size,ftr2);
remove("b.JPG");
}
// a란파일을 읽고 b라는 파일을 버퍼에 복사, 복사한 뒤 b는 삭제
fclose(ftr1);
fclose(ftr2);
strcpy(response_body); // response_body
write(client_fd,buf,size);
sprintf(response_body,"%s",strsum1);
sprintf(response_header,
"HTTP/1.0 200 OK \r \n"
"Server:2019 simple web server \r \n"
"Content-length:%lu\r\n"
"Content-Type:image/*\r\n\r\n",strlen(response_message));
}
write(client_fd,response_header,strlen(response_header));
write(client_fd,response_body,strlen(response_body));
printf("%s %d client was disconnected\n", inet_ntoa(inet_client_address),client_addr.sin_port);
close(client_fd);
}
close(socket_fd);
return 0;
}
글 내용 입력하는 textarea 에 아래와 같이
글 내용 입력하는 textarea 에 아래와 같이 출력 되고 있는데 못 보셨나요?
최신 브라우저를 사용한다면 못 보신게 아니라 무시하신 거겠죠.
이런 사소해 보이는 가이드라인을 대충 지나치는 대신
이런 사소해 보이는 가이드라인을 대충 지나치는 대신 꼼꼼히 읽고 따를 줄 아는 사람이라면,
프로그래밍 관련 QnA 게시판에 질문을 올릴 일이 그다지 많지 않을 겁니다.
역설적인 일이지요. 하지만 어쩌겠습니까...
... 그보다는 글 내용 textarea 아래의 텍스트 양식 dropdown 메뉴 기본값을, Filtered HTML 말고 Plain text로 하는 건 어떨까요?
indentation은 여전히 깨지겠지만 최소한 <stdio.h> 같은 텍스트가 깨져서 날아가는 건 막을 수 있을 것 같은데요.
댓글 달기