오늘 수업시간에는 채팅프로그램을 제작하는 시간을 가졌습니다
어제 소스를 분석하지 않고 넘어가서 분석을 한번 해보도록 하겠습니다
본격!! 시키지도 않았는데 열심히 분석하는...ㅋㅋ
=[echo_server_sel.c소스예제]=
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<unistd.h>
#include
<sys/types.h>
#include
<sys/socket.h>
#include
<netinet/in.h>
#define
BUFSIZE 100
void
error_handling(char *message);
int
main(int argc, char *argv[])
{
int serv_sock;
struct sockaddr_in serv_addr;
fd_set reads, temps;
int fd_max;
char message[BUFSIZE];
int str_len;
struct timeval timeout;
if(argc != 2)
{
printf("Usage: %s PortNum \n", argv[0]);
exit(1);
}
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(argv[1]));
if( bind(serv_sock, (struct sockaddr *)&serv_addr,sizeof(serv_addr)))
error_handling("bind() error");
if(listen(serv_sock,5) == -1)
error_handling("listen() error");
FD_ZERO(&reads);
FD_SET(serv_sock, &reads);
fd_max = serv_sock;
while(1)
{
int fd, str_len;
int clnt_sock, clnt_len;
struct sockaddr_in clnt_addr;
temps = reads;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if(select(fd_max+1, &temps,0,0, &timeout) == -1)
error_handling("select() error");
for(fd=0;fd<fd_max+1;fd++)
{
if(FD_ISSET(fd, &temps))
{
if(fd == serv_sock)
{
clnt_len = sizeof(clnt_addr);
clnt_sock = accept(serv_sock,(struct sockaddr *)&clnt_addr, &clnt_len);
FD_SET(clnt_sock, &reads); //read
에
clnt_sock
등록
if(fd_max<clnt_sock)
fd_max = clnt_sock;//
개수
갱신
printf("client
접속
:
소켓
디스크립터
%d \n"
, clnt_sock);
}
else //clnt_sock
에
변화가
있는
경우
{
str_len = read(fd, message, BUFSIZE);
if(str_len == 0)//
연결
종료
요청인
경우
{
FD_CLR(fd, &reads);
close(fd);
printf("client
종료
:
소켓디스크립터
%d \n"
, fd);
}
else
{
write(fd, message, str_len);
}
}
}
}
}
return 0;
}
void
error_handling(char *message)
{
fputs(message,stderr);
fputc('\0',stderr);
exit(1);
}
echo_server_sel소스를 순서대로 분석을 해보겠습니다 실제 프로그램이 실행되는 동안에 어떤값이 들어있고 어떤순서로 진행되는지 제대로 (제가)파악을 못하고 있는 것 같아서 해보게 되었습니다 혹시나 잘못 이해하고 있는 부분이 있다면 지적하여 주세요~!!
프로그램이 실행되는 순서대로 한번 따라가 보겠습니다
참고>>select()함수에 필요한 헤더파일
#include
<unistd.h>
#include
<sys/types.h>
다음으로 main함수로 들어가겠습니다
fd_set reads, temps;
int fd_max;
struct timeval timeout;
변수가 선언되어 있습니다
select함수를 사용하기 위해서 fd_set에 reads와 원본값을 들고 있기 위한 temps 그리고 파이디스크립터 검사 범위설정을 위하여 fd_max를 선언해두었습니다 그리고 시간을 식별하기 위한 timeval구조체가 선언되어있습니다
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
조금 더 내려가면 main의 인자 값을 체크하고 있고 거기서 조금더 내려가면 sock초기화가 나옵니다 socket 반환값을 알고 싶어서 printf(“%d\n”, serv_sock); 해보니 3라는 값을 알 수 있었습니다
bind와 listen을 하고 나면 FD값의 초기화가 나옵니다 초기화가 되어지는 순서를 그림으로 표현하면 다음과 같습니다
FD_ZERO(&reads);
fd0 |
fd1 |
fd2 |
fd3 |
fd4 |
...... |
0 |
0 |
0 |
0 |
0 |
...... |
FD_SET(serv_sock, &reads);
fd0 |
fd1 |
fd2 |
fd3 |
fd4 |
...... |
0 |
0 |
0 |
1 |
0 |
...... |
fd_max = serv_sock;
그리고 fd_max에는 3을 가지고 있습니다
while(1)
{
int fd, str_len;
int clnt_sock, clnt_len;
struct sockaddr_in clnt_addr;
temps = reads;
while문은 항상 참으로 무한으로 반복합니다 클라이언트 소켓과 관련된 변수를 선언해주고 앞에서 읽었던 reads를 temps에 넣어 초기화를 시켜줍니다 그럼 temps의 값은
fd0 |
fd1 |
fd2 |
fd3 |
fd4 |
...... |
0 |
0 |
0 |
1 |
0 |
...... |
이 됩니다~~
timeout.tv_sec = 5;
timeout.tv_usec = 0;
_sec는 초를 뜻하는 단위이고 _usec 마이로 세컨드를 뜻하는 단위입니다 5,0 이란 말은 5초동안을 뜻합니다 _usec에 값을 넣으면 _sec시간과 합쳐진 만큼 동작시간을 가지게 됩니다 즉 마이크로 세컨드가 백만분의 1초이니 여기다 백만을 넣고 _sec에 5를 넣으면 6초간 이라는 의미가 됩니다
if
(select(fd_max+1, &temps,0,0, &timeout) == -1)
fd0 |
fd1 |
fd2 |
fd3 |
fd4 |
...... |
0 |
0 |
0 |
1 |
0 |
...... |
select함수는 (검색 대상이되는 파일디스크립터수, 읽기, 쓰기, 오류, 시간)을 담고 있는데 현제 fd_max에 1을 더한 만큼 범위를 설정하면 계산할 범위를 설정할수있습니다 fd_mac가 3이니 +1하면 4가 되어있습니다 -1은 오류를 뜻하니 오류가 발생하지 않아서 아래로 내려갑니다 정확하게 이야기하자면 5초동안 대기한후 아래로 내려갑니다
for(fd=0;fd<fd_max+1;fd++)
{
if(FD_ISSET(fd, &temps))
{
이제 for문에서 fd0부터 fd_max+1한 만큼 범위를 검사합니다 그래서 FD_ISSET으로 값이 발견되면 if문 안으로 들어가게 됩니다 현제 fd가 4일때 if문 안으로 들어갑니다
if(fd == serv_sock)
{
clnt_len = sizeof(clnt_addr);
clnt_sock = accept(serv_sock,(struct sockaddr *)&clnt_addr, &clnt_len);
여기까지 진행하고 accept를 시켜주지 않으면 5초후 다시 반복하게 됩니다printf문으로 출력해보니 fd값이 if문안에서 3까지 증가(0,1,2,3)하는 것을 확인할 수있었습니다 client의 연결이 허락된 후에는 clnt_sock에는 4라는 값이 들어오게됩니다
FD_SET(clnt_sock, &reads); //read
에
clnt_sock
등록
fd0 |
fd1 |
fd2 |
fd3 |
fd4 |
...... |
0 |
0 |
0 |
0 |
1 |
...... |
fd4에 clnt_sock으로 세팅을 하였습니다
if
(fd_max<clnt_sock)
fd_max = clnt_sock;//
개수
갱신
현재 fd_max는 while문 밖에서 3이라는 값을 가지고 왔고 clnt_sock은 4라는 값을 가지고 있기 때문에 if(3<4)참이 됩니다 fd_max값이 이제는 clnt_sock 값으로 초기화되게 됩니다. printf로 fd를 돌려보니 0,1,2,3 으로 증가하다 client접속후에는 0,1,2,3,4까지 증가하는 것을 확인 할 수 있었습니다
else //clnt_sock
에
변화가
있는
경우
{
str_len = read(fd, message, BUFSIZE);
앞에서 clnt의 변화가 있었기 때문에 현재 연결되어 있는 상태입니다 read에 와서 block되어 있는 상태 입니다 client에서 접속을 끝게되면 EOF ‘0’을 반환하게 되어 종료하게 됩니다
if(str_len == 0)//
연결
종료
요청인
경우
{
FD_CLR(fd, &reads);
close(fd);
printf("client
종료
:
소켓디스크립터
%d \n"
, fd);
}
종료하면서 fd가 가리키는 곳을 0으로 클릭어 하게됩니다
fd0 |
fd1 |
fd2 |
fd3 |
fd4 |
...... |
0 |
0 |
0 |
0 |
0 |
...... |
else
{
write(fd, message, str_len);
}
종료가 아닐경우 else문으로 들어가 읽어드린 message를 쓰고 있습니다
그리고 다시 while문으로 가서 초기화됩니다
temps = reads;
fd0 |
fd1 |
fd2 |
fd3 |
fd4 |
...... |
0 |
0 |
0 |
0 |
1 |
...... |
void error_handling(char *message)
는 생략합니다~....
select()함수가 실행시 5초간의 유지시간 중에 값의 변화가 생기면 즉 client의 접속이 발생할 경우 for문에 있던 accept도 같이 실행되게 됩니다 client접속이 들어오게 되면 바로 접속 성공메시지 발생하기 때문인 것 같습니다
=[JAVA의 배열]=
예제를 통하여 java배열의 형태를 살펴 봅시다
예제1)
int [] a = new int[10];
=int a[] = new int[10]; 허용합니다
예제2) 케릭터형 배열을 선언과 동시에 초기화를 하시오
char [] b = {‘a’,’b’,’c’}
예제3)초기화를 하지 않았다면 선언후에 초기화는 어떻게 하는가?
a[0] = 1;
a[1] = 2;
예제4)
1 |
3 |
5 |
7 |
출력
1 3 5 7
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] odd = new int[4];
int cnt = 1;
for(int i=0;i<odd.length;i++)
{
odd[i] = cnt;
cnt += 2;
System.out.print(odd[i]+ " ");
}
}
참고
odd.length = 배열의 길이만큼을 뜻합니다
예제5)char alpha[26]만들고
A B C D ... Z까지 출력하시오~~
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] alpha = new char[26];
char cnt = 0;
for(char i='A';i<='Z';i++)
{
alpha[cnt] = i;
System.out.print(alpha[cnt++]+ " ");
}
}
보너스 문제 소문자 z y x....a순으로 넣고 z y x....a순으로 출력하시오
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] alpha = new char[26];
char cnt = 0;
for(char i='z';i>='a';i--)
{
alpha[cnt] = i;
System.out.print(alpha[cnt++]+ " ");
}
}
예제를 통하여 1차원 배열에 대하여 살펴보았습니다
=[2차원배열]=
(2차원 배열의 선언)
int [][] array = new int [5] [5];
ê행ê열
그럼 역시 2차원 배열도 예제를 통하여 살펴 보도록 하겠습니다
(C와는 참 비슷하게 생겼습니다!!)
예제1)다음과 같이 만들어 보시오
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 |
public static void main(String[] args) {
// TODO Auto-generated method stub
int [][] array = new int[5][5];
int cnt = 1;
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++,cnt++)
{
array[i][j] = cnt;
System.out.print(array[i][j] + "\t");
}
System.out.print("\n");
}
}
예제2)다음과 같이 만들어 보시오
A |
F |
K |
P |
U |
B |
G |
L |
Q |
V |
C |
H |
M |
R |
W |
D |
I |
N |
S |
X |
E |
J |
O |
T |
Y |
public static void main(String[] args) {
// TODO Auto-generated method stub
char [][] array = new char[5][5];
char cnt = 'A';
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++,cnt++)
{
array[j][i] = cnt; }
}
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++,cnt++)
{
System.out.print(array[i][j] + "\t");
}
System.out.print("\n");
}
}
java 의 배열 역시 객체입니다 그래서 위 그림과 같이 C와는 다르게 heap영역에 생성이 되고 초기화 됩니다.!!
'코스웨어 > 11년 내장형하드웨어' 카테고리의 다른 글
[내장형]윤민석 2011년 8월 8일 수업내용 (10) | 2011.08.09 |
---|---|
[내장형]최남식-2011년07월29일 일일보고서 (13) | 2011.07.29 |
20110728 일일보고서 (상속) _ 이성재 (12) | 2011.07.28 |
[내장형]김수만_2011년7월27일_일일보고서(선생님의 채팅프로그램 소스코드(chat_server.c, chat_client.c)의 전체적인 흐름과 분석, 네트워크프로젝트 계획), JAVA String Class, toString(), charAt(), equals(), substring() 메소드를 사용한 예제4개 (16) | 2011.07.27 |
[내장형]하드웨어 최성태 (10) | 2011.07.25 |
[내장형]윤병도_20110722 JAVA(클래스,getter/setter함수),멀티플렉싱(select함수) (17) | 2011.07.22 |
[내장형]공정우-2011.7.21(목) 일일보고서 (9) | 2011.07.22 |
[내장형]김수만_배고픈 금붕어 관찰일지 >_< (19) | 2011.07.21 |