소스보기 접기
/* talk_server.c
서버와 클라이언트가 따로 종료 */
#include < stdio.h>
#include < string.h>
#include < stdlib.h>
#include < sys/types.h>
#include < stdio.h>
#include < string.h>
#include < stdlib.h>
#include < sys/types.h>
#include < signal.h>
#include < sys/socket.h>
#include < netinet/in.h>
#include < arpa/inet.h>
#include < unistd.h>
#include < sys/wait.h>
#define MAXLINE 512
char *escapechar = "exit" ; //종료문자열
void z_handler(); //시그널 처리함수
int main(int argc, char *argv[])
{
int server_sock;
int client_sock;
int clntlen;
int num;
int size;
char sendline[MAXLINE];
char recvline[MAXLINE];
pid_t fork_ret;
struct sockaddr_in client_addr;
struct sockaddr_in server_addr;
struct sigaction act; //signal 사용하기 위해 추가된 변수
act.sa_handler = z_handler; //signal 설정
if (2 != argc)
{
printf("Usage : %s PORT \n" , argv[0 ]);
return 0 ;
}
/* 소켓 생성 */
if (0 > (server_sock = socket(PF_INET, SOCK_STREAM, 0 )))
{
printf("Server : can't open stream socket. \n" );
return 0 ;
}
/* 소켓주소 구조체에 주소 세팅 */
bzero((char *)& server_addr, sizeof (server_addr)); //소켓주소 구조체 초기화
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(atoi(argv[1 ]));
sigaction(SIGCHLD, & act, 0 ); //자식프로세스 종료시 발생하는 시그널 SIGCHLD이용
/* 소켓에 서버 주소 연결 */
if (0 > bind(server_sock, (struct sockaddr *)& server_addr, sizeof (server_addr)))
{
printf("Server : can't bind local address. \n" );
return 0 ;
}
printf("Server started. \nWaiting for client.. \n" );
listen(server_sock, 1 );
/* 클라이언트의 연결요청 수락 */
clntlen = sizeof (client_addr);
if (0 > (client_sock = accept(server_sock, (struct sockaddr *)& client_addr, & clntlen)))
{
printf("server : failed in accepting. \n" );
return 0 ;
}
if (0 < (fork_ret = fork()))
{
/* 부모 프로세스는 클라이언트로부터 수신된 메시지를 화면에 출력 */
while (1 )
{
if (0 > (size = read(client_sock, recvline, MAXLINE)))
{
printf("Error if read. \n" );
close(client_sock);
return 0 ;
}
recvline[size] = '\0' ;
printf("%s" , recvline); //화면출력
}
}
else if (0 = = fork_ret)
{
/* 자식 프로세스는 키보드 입력을 클라이언트로 송신 */
while (NULL != fgets(sendline, MAXLINE, stdin))
{
size = strlen(sendline);
if (size != write(client_sock, sendline, strlen(sendline)))
{
printf("Error in write. \n" );
}
if (NULL != strstr(sendline, escapechar)) //종료문자열 입력시 처리
{
printf("Good bye. \n" );
close(client_sock);
return 0 ;
}
printf("%s" , recvline); //화면출력
}
}
close(server_sock);
close(client_sock);
return 0 ;
}
/* 시그널 처리함수 */
void z_handler()
{
int state;
waitpid(-1 , & state, WNOHANG);
exit(0 ); //자식이 종료되면 부모도 같이 종료.
}
접기
소스보기 접기
/* talk_client.c */
#include < stdio.h>
#include < string.h>
#include < stdlib.h>
#include < sys/types.h>
#include < signal.h>
#include < sys/socket.h>
#include < netinet/in.h>
#include < arpa/inet.h>
#include < sys/wait.h>
#include < unistd.h>
#define MAXLINE 1024
char *escapechar = "exit" ; //종료문자열
void z_handler();
int main(int argc, char *argv[])
{
char line[MAXLINE];
char sendline[MAXLINE];
char recvline[MAXLINE];
int n;
int size;
int comp;
int addr_size;
int state;
pid_t fork_ret;
static int s;
static struct sockaddr_in server_addr;
struct sigaction act;
act.sa_handler = z_handler;
if (3 != argc)
{
printf("Usage : %s server IP serverPORT \n" , argv[0 ]);
return 0 ;
}
/* 소켓 생성 */
if (0 > (s = socket(PF_INET, SOCK_STREAM, 0 )))
{
printf("Client : can't open stream socket. \n" );
return 0 ;
}
/* 소켓주소 구조체에 접속할 서버 주소 세팅 */
bzero((char *)& server_addr, sizeof (server_addr)); //소켓주소 구조체 초기화
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(argv[1 ]);
server_addr.sin_port = htons(atoi(argv[2 ]));
state = sigaction(SIGCHLD, & act, 0 );;
/* 서버에 연결 요청 */
if (0 > connect(s, (struct sockaddr *)& server_addr,sizeof (server_addr)))
{
printf("Client : can't connect to server. \n" );
return 0 ;
}
fork_ret = fork();
if (0 < fork_ret)
{
/* 부모 프로세스는 서버로부터 수신된 메시지를 화면에 출력 */
while (1 )
{
if (0 > (size = read(s, recvline, MAXLINE)))
{
printf("Error if read. \n" );
close(s);
return 0 ;
}
recvline[size] = '\0' ;
if (NULL != strstr(recvline, escapechar)) //종료문자열 입력시 처리
{
// break;
}
printf("%s" , recvline); //화면 출력
}
}
else if (0 = = fork_ret)
{
/* 자식 프로세스는 키보드 입력을 서버로 송신 */
while (NULL != fgets(sendline, MAXLINE, stdin))
{
size = strlen(sendline);
if (size != write(s, sendline, strlen(sendline)))
{
printf("Error in write. \n" );
}
if (NULL != strstr(sendline, escapechar)) //종료문자열 입력시 처리
{
printf("Good bye. \n" );
close(s);
return 0 ;
}
}
}
close(s);
return 0 ;
}
void z_handler()
{
int state;
waitpid(-1 , & state, WNOHANG);
exit(0 );
}
접기
서버측에서 exit를 입력하면 서버측 자식프로세스가 먼저 종료되고 시그널이 발생한다.
시그널이 발생하면 시그널 처리함수가 실행되어 자식프로세스의 리턴값을 받고 부모프로세스도 종료된다.
남은 클라이언트측은 아직 실행 되고 있다.
클라이언트측도 마찬가지로 exit를 입력하면 자식프로세스가 소멸되면 부모프로세스도 같이 종료된다.
Package에 도메인네임을 거꾸로 적어 넣는다
Name에는 이름을 적는다
public static void main(String[] args)를 체크하면 자동으로 메인을 생성해준다
<다음을 출력하세요>
안녕하세요 자바!
반갑습니다. 내장형 하드웨어!
홍
홍길
홍길동
3 + 5 = 8
7 – 3 = 4
리터럴(Liter)상수 - 메모리는 차지하지만 이름이 없어 리터럴상수라고 한다
자바에서는 System.out.println 을 사용하여 출력한다
System - 클래스
out - 객체
println - 출력
<다음을 출력하세요>
1 ~ 100까지 합은 5050이다.
for문 사용.
[출력]
5050
<키보드로 부터 입력을 받는 ScannerTest Project >
Scanner input = new Scanner(System.in); 을 사용하여 키보드 입력을 설정한다
Scanner - 클래스
input - 객체
new - heap영역 할당
Scanner(System.in) - 키보드 입력
<다음을 출력하세요>
[입력]
3
4
[출력]
3 + 4 = 7
<다음을 출력하세요>
[입력]
입력값:
3
5
[출력]
3 + 5 = 8
3 – 5 = –2
3 * 5 = 15
3 / 5 = 0.6 (double) 사용
Java에서는 char는 2byte를 나타낸다
저장 클래스(Storage Class - 분류)
C 언어에서 변수와 함수는 저장 클래스를 가진다. 저장 클래스는 변수와 함수의 지속기간(duration) 유효범위(scope)를 명시해 준다. 저장 클래스의 설정이유는 변수와 함수에 지속기간과 유효범위를 부여함으로써 메모리를 효율적으로 사용하고 프로그래밍 오류를 줄이기 위해서이다. 저장 클래스에는 auto, register, static, extern의 네 가지가 있다.
지속기간
- 지속기간은 프로그램의 실행 중에서 시간상으로 존재하는 기간을 말한다.
*auto 클래스는 가장 많이 사용되는 것으로 함수 내에서 저장 클래스를
명시하지 않고 사용되는 변수들이다.
*auto 클래스의 변수는 함수 내에서 선언되어 함수가 실행을 시작할 때
생성되어 함수가 실행을 종료되면 소멸된다.
*register 클래스는 컴파일러가 CPU의 레지스터 중 하나를 이 변수로
사용하게 한다. 따라서 register 변수의 크기는 register의 크기보다 클 수 없다.
*또 레지스터의 숫자가 작으므로 프로그램 내에서 register로 선언된
변수라도 컴파일러가 레지스터를 배정하지 않을 수 있다.
*register 클래스도 auto 클래스와 마찬가지로 함수의 실행과 함께
생성되었다가 함수의 실행이 종료되면 소멸된다.
*static 클래스와 extern 클래스는 auto 클래스나 register 클래스와는
달리 함수의 실행이 끝난뒤에도 남아있는 변수이다.
*static 클래스는 함수의 내부에서나나 외부에서 모두 선언될 수 있고
extern 클래스는 함수의 외부에서만 선언된다.
*static 변수는 초기화를 하지 않아도 시스템에 의해서 자동적으로
0이나 NULL로 초기화 된다.
소스보기 접기
#include < stdio.h>
int a2 = 12 ; //Data영역
int a3; //BSS영역
void test(void );
int main()
{
static int a; //static는 BSS영역
int b;
static int a1;
static int a4 = 100 ; //초기화를 하면 Data영역으로 간다
static int a5;
static int a6;
static int a7 = 5 ;
static int a8;
static int a9;
static int a10;
printf("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = \n" );
printf("a 주소 :%08X\n" , & a);
printf("b 주소 :%08X\n" , & b);
printf("main주소 :%08X\n" , main);
printf("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = \n" );
printf("a의 값 :%d\n" , a);
printf("b의 값 :%d\n" , b);
printf("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = \n" );
printf("a1 주소 :%08X\n" , & a1);
printf("a2 주소 :%08X\n" , & a2);
printf("a3 주소 :%08X\n" , & a3);
printf("a4 주소 :%08X\n" , & a4);
printf("a5 주소 :%08X\n" , & a5);
printf("a6 주소 :%08X\n" , & a6);
printf("a7 주소 :%08X\n" , & a7);
printf("a8 주소 :%08X\n" , & a8);
printf("a9 주소 :%08X\n" , & a9);
printf("a10 주소 :%08X\n" , & a10);
test();
return 0 ;
}
void test(void )
{
printf("a2 값 :%d\n" , a2);
return ;
}
접기
<결과>
a1~ a10까지의 변수들중
빨간 네모안에 있는 주소는 Data영역을 가리키고,
나머지 주소들은 BSS영역을 가리킨다
static 클래스는 초기화 하지 않으면 BSS영역을 초기화 하면 Data영역으로 바뀐다.
전역변수 또한 초기화 하지 않으면 BSS영역을 초기화 하면 Data영역으로 바뀐다.
전역변수의 장점으로는 함수간 공유가 쉽다