리눅스 소켓통신에서 바이너리 데이터를 어떻게 보내야 될까요??

익명 사용자의 이미지

리눅스에서 실행파일이나 이미지파일의 데이터를 읽어서 보내려고 합니다.
두 개 다 바이너리 파일인데 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))와같은 형식으로 데이터를 전송했으나 데이터는 잘 전송이 되나 이걸 이미지로 읽지를 못하네요. 제가 어떤 부분에서 실수를 한 건가요??

라스코니의 이미지

전형적인 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 에 아래와 같이 출력 되고 있는데 못 보셨나요?
최신 브라우저를 사용한다면 못 보신게 아니라 무시하신 거겠죠.

이 내용은 글 입력시에 자동으로 삭제 됩니다.

코드 입력 또는 들여쓰기가 필요한 내용의 경우,
<code> tag block 을 이용하여 작성 하십시오.

For code entry or indentation, use the <code> tag block.

<code lang="c">
if ( a != b ) {
    printf ("different a and b\n&qout;);
} else {
    printf ("same a and b\n");
}
</code>
익명 사용자의 이미지

이런 사소해 보이는 가이드라인을 대충 지나치는 대신 꼼꼼히 읽고 따를 줄 아는 사람이라면,

프로그래밍 관련 QnA 게시판에 질문을 올릴 일이 그다지 많지 않을 겁니다.

역설적인 일이지요. 하지만 어쩌겠습니까...

... 그보다는 글 내용 textarea 아래의 텍스트 양식 dropdown 메뉴 기본값을, Filtered HTML 말고 Plain text로 하는 건 어떨까요?

indentation은 여전히 깨지겠지만 최소한 <stdio.h> 같은 텍스트가 깨져서 날아가는 건 막을 수 있을 것 같은데요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.