실습3: 앞서 실습한 file_server.c, file_client.c 는 server에서 client 접속시 파일을 전송한다. 이번에는 반대로 서버는 select를 이용해 구현하고, client에서 파일을 전송하도록 해보자, //echo_selectserv.c 사용해도댐
( 어제한건 서버->클라로 파일 전송 )
file_client.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
// client.c
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int sd;
FILE *fp;
char buf[BUF_SIZE];
int read_cnt;
int clnt_sd;
struct sockaddr_in serv_adr;
if(argc!=3) {
printf("Usage: %s <IP> <port>\n", argv[0]);
exit(1);
}
sd=socket(PF_INET, SOCK_STREAM, 0);
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]));
clnt_sd=connect(sd, (struct sockaddr*)&serv_adr, sizeof(serv_adr));
while(1)
{
read_cnt=fread((void*)buf,1,BUF_SIZE,fp);
if(read_cnt<BUF_SIZE)
{
write(sd, buf, read_cnt);
break;
}
write(sd, buf, BUF_SIZE);
}
fclose(fp);
close(sd);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n',stderr);
exit(1);
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs |
표준 입출력 함수의 장점
표준 입출력 함수의 두 가지 장점
- 표준 입출력 함수는 이식성(Protability)이 좋다.
- 표준 입출력 함수는 버퍼링을 통한 성능의 향상에 도움이 된다.
ANSI C 기반의 표준 입출력 함수는 모든 컴파일러에서 지원을 하기 때문에 이식성이 좋아진다.
표준 입출력 함수와 시스템 함수의 성능비교
dd if=/dev/zero of=test100M count=1 bs=100M
syscpy.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include <stdio.h>
#include <fcntl.h>
#define BUF_SIZE 3
int main(int argc, char *argv[])
{
int fd1, fd2, len;
char buf[BUF_SIZE];
fd1=open("news.txt", O_RDONLY);
while((len=read(fd1, buf, sizeof(buf)))>0)
write(fd2, buf, len);
close(fd1);
close(fd2);
return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs |
시스템 함수를 이용해서 버퍼링 없는 파일 복사를 진행
stdcpy.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include <stdio.h>
#define BUF_SIZE 3
int main(int argc, char *argv[])
{
FILE * fp1;
FILE * fp2;
char buf[BUF_SIZE];
while(fgets(buf, BUF_SIZE, fp1)!=NULL)
fputs(buf, fp2);
fclose(fp1);
fclose(fp2);
return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs |
표준 입출력 함수를 이용해서 버퍼링 기반의 파일 복사를 진행
표준 입출력 함수의 사용에 있어서 불편사항
리눅스에서의 send & recv
#include <sys/socket.h>
ssize_t send(int sockfd, const void * buf, size_t nbytes, int flags);
- sockfd 데이터 전송 대상과의 연결을 의미하는 소켓의 파일 디스크립터 전달.
- buf 전송할 데이터를 저장하고 있는 버퍼의 주소 값 전달.
- nbytes 전송할 바이트 수 전달
- flags 데이터 전송 시 적용할 다양한 옵션 정보 전달.
ssize_t recv(int sockfd, void * buf, sizt_t nbytes, int flags);
- sockfd 데이터 수신 대상과의 연결을 의미하는 소켓의 파일 디스크립터 전달
- buf 수신된 데이터를 저장할 버퍼의 주소 값 전달.
- nbytes 수신할 수 있는 최대 바이트 수 전달
- flags 데이터 수신 시 적용할 다양한 옵션 정보 전달
옵션(Option) | 의미 | send | recv |
MSG_OOB | 긴급 데이터(Out-of-band data)의 전송을 위한 옵션 |
● |
● |
MSG_PEEK | 입력버퍼에 수신된 데이터의 존재유무 확인을 위한 옵션 |
● |
|
MSG_DONTROUTE | 데이터 전송과정에서 라우팅(Routing) 테이블을 참조하지 않을 것을 요구하는 옵션, 따라서 로컬(Local) 네트워크 상에서 목적지를 찾을 때 사용되는 옵션 |
● |
|
MSG_DONTWAIT | 입출력 함수 호출과정에서 블로킹 되지 않을 것을 요구하기 위한 옵션, 즉, 넌-블로킹(Non-blocking) IO의 요구에 사용되는 옵션 |
● |
● |
MSG_WAITALL | 요청한 바이트 수에 해당하는 데이터가 전부 수신될 때까지, 호출된 함수가 반환되는 것을 막기 위한 옵션 |
● |
데이터의 전송에 사용되는 옵션정보이다. 옵션정보는 | 연산자를 이용해서 둘 이상을 동시에 지정 가능하다. 그러나 옵션의 종류와 지원여부는 운영체제에 따라서 차이가 있다.
MSG_OOB : 긴급 메시지의 전송
oob_send.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in recv_adr;
if(argc!=3) {
printf("Usage : %s <IP> <port>\n", argv[0]);
exit(1);
}
sock=socket(PF_INET, SOCK_STREAM, 0);
memset(&recv_adr, 0, sizeof(recv_adr));
recv_adr.sin_family=AF_INET;
recv_adr.sin_addr.s_addr=inet_addr(argv[1]);
recv_adr.sin_port=htons(atoi(argv[2]));
if(connect(sock, (struct sockaddr*)&recv_adr, sizeof(recv_adr))==-1)
error_handling("connect() error!");
write(sock, "123", strlen("123"));
send(sock, "4", strlen("4"), MSG_OOB);
write(sock, "567", strlen("567"));
send(sock, "890", strlen("890"), MSG_OOB);
close(sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs |
MSB_OOB 메시지를 받으면 SIGURG 시그널이 발생한다. 따라서 이에 대한 처리를 위해서 시그널 핸들링이 필요하다. 단, fcntl 함수의 호출을 통해 해당 소켓의 소유자를 현재 실행중인 프로세스로 변경해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#define BUF_SIZE 30
void error_handling(char *message);
void urg_handler(int signo);
int acpt_sock;
int recv_sock;
int main(int argc, char *argv[])
{
struct sockaddr_in recv_adr, serv_adr;
int str_len, state;
socklen_t serv_adr_sz;
struct sigaction act;
char buf[BUF_SIZE];
if(argc!=2) {
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
act.sa_handler=urg_handler;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
acpt_sock=socket(PF_INET, SOCK_STREAM, 0);
memset(&recv_adr, 0, sizeof(recv_adr));
recv_adr.sin_family=AF_INET;
recv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
recv_adr.sin_port=htons(atoi(argv[1]));
if(bind(acpt_sock, (struct sockaddr*)&recv_adr, sizeof(recv_adr))==-1)
error_handling("bind() error");
listen(acpt_sock, 5);
serv_adr_sz=sizeof(serv_adr);
recv_sock=accept(acpt_sock, (struct sockaddr*)&serv_adr, &serv_adr_sz);
fcntl(recv_sock, F_SETOWN, getpid());
state=sigaction(SIGURG, &act, 0);
while((str_len=recv(recv_sock, buf, sizeof(buf), 0))!= 0)
{
if(str_len==-1)
continue;
buf[str_len]=0;
puts(buf);
}
close(recv_sock);
close(acpt_sock);
return 0;
}
void urg_handler(int signo)
{
int str_len;
char buf[BUF_SIZE];
str_len=recv(recv_sock, buf, sizeof(buf)-1, MSG_OOB);
buf[str_len]=0;
printf("Urgent message: %s \n", buf);
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs |
실행 결과를 보면, 긴급으로 메시지가 전달 된 흔적이 보이지 않는다. 이렇듯 MSG_OOB는 우리가 생각하는 긴급의 형태와 다르다.
실행결과의 판단
MSG_OOB 메시지라고 해서 더 빨리 전송되지 않는다.
긴급으로 보낸 메시지의 양에 상관 없이 1바이트만 반환이 된다.
'딥러닝 기반 영상인식 개발 전문가 과정 > 리눅스' 카테고리의 다른 글
6월14일 채팅실습, fileno, fdopen, 입력 스트림과 출력 스트림의 분리 (0) | 2019.06.14 |
---|---|
6월13일 채팅, 실습 (0) | 2019.06.13 |
6월13일 실습, IO Multiplexing, select (0) | 2019.06.13 |
6월12일 프로세스 기반 다중접속 서버 모델, TCP, 소켓의 다른 옵션 (0) | 2019.06.12 |
6월 11일 echo,op server/client 소스, UDP (0) | 2019.06.11 |