간단한 팁이지만 잊어버릴까봐 남겨두고자 합니다.
C#에서 문자는 유니코드로 표현됩니다. 유니코드는 영어 뿐만 아니라 다른 언어들도 표현하기 위한 코드로 세계 대부분의 언어를 표현할수 있습니다. 정확한 알고 있는 것은 아니지만 아시아의 4개 국가(일본, 중국, 한국, 베트남)이 같은 카테고리로 묶여 있는 것으로 알고 있습니다. 어찌되었든 System.Globalization.UnicodeCategory에 보시면 여러가지 카테고리들이 있습니다. 한글은 OtherLetter에 포함되어 있구요. 밑에 코드 처럼 판별하고자 하는 문자와 같은 카테고리의 속한 경우를 체크하면 한글인지, 영어인지, 숫자인지 등을 판단할 수 있을것입니다.
static void Main(string[] args)
{
string s = "가나다";
char[] charArr = s.ToCharArray();
foreach(char c in charArr)
{
if(char.GetUnicodeCategory(c) == System.Globalization.UnicodeCategory.OtherLetter)
{
Console.WriteLine("한글입니다");
}
}
Console.Read();
}
위 코드로는 영어/숫자/그외 언어(한글,한자,일어 등) 정도로 구분할 수 있습니다. 좀 더 정확한 판단을 위해서는 해당 문자열의 유니코드 코드를 구해 비교해야 합니다. (참고 URL : http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&pageno=0&wid=1294&rssMode=1&wtype=0)
.NET 프레임워크에서는 프린터로 출력하기위한 여러가지 출력 기능을 제공해줍니다.
바로 PrintPreviewDialog 클래스와 PrintDocument 클래스입니다.
PrintPreviewDialog 클래스는 미리보기를 생성해주는 클래스고 PrintDocument 클래스는 출력하기 위한 데이터를 지정해주는 클래스입니다.
즉 PrintPrewviewDialog 클래스로 미리보기 창을 생성해주고 PrintDocument 클래스로 데이터를 넘겨준다음 PrintPreviewDialog 클래스와 연결시켜주면 됩니다.
여러 페이지를 출력하고자 할때는 e.HasMorePages을 true로 주시면 됩니다. e.HasMorePages는 출력하고자 하는 페이지가 더 있는지를 체크해주는 값으로 false이면 뒤에 더이상 데이터가 없다는 것을 나타냅니다.
여기서 한가지 주의해야 할 점은 출력해야 할 페이지가 여러페이지일 경우 document 객체에 BeginPrint 이벤트를 재정의 해주어야 한다는 것입니다. 왜냐하면 미리보기에서 프린트 버튼을 클릭해서 출력하려고 할때 BeginPrint 이벤트가 호출되면서 다시 한번 document를 전부 호출해서 출력하기 때문입니다. 만약에 BeginPrint를 재정의 하지 않으면 미리보기 창을 띄울 때 curpageNumber이 감소되어 0이 되어 있기 떄문에 마지막 페이지만 출력이 될 수 도 있습니다.
public partial class Form1 : Form
{
internal PrintPreviewDialog PrintPreviewDialog1;
private System.Drawing.Printing.PrintDocument document = new System.Drawing.Printing.PrintDocument();
private int curPageNumber;
private int curPageNumber_bak;
public Form1()
{
InitializeComponent();
this.PrintPreviewDialog1 = new PrintPreviewDialog();
curPageNumber = 1;
//Set the size, location, and name.
this.PrintPreviewDialog1.ClientSize =
new System.Drawing.Size(400, 300);
this.PrintPreviewDialog1.Location =
new System.Drawing.Point(29, 29);
this.PrintPreviewDialog1.Name = "PrintPreviewDialog1";
// Associate the event-handling method with the
// document's PrintPage event.
this.document.PrintPage +=
new System.Drawing.Printing.PrintPageEventHandler
(document_PrintPage);
this.document.BeginPrint += new System.Drawing.Printing.PrintEventHandler(document_BeginPrint);
// Set the minimum size the dialog can be resized to.
this.PrintPreviewDialog1.MinimumSize =
new System.Drawing.Size(700, 700);
// Set the UseAntiAlias property to true, which will allow the
// operating system to smooth fonts.
this.PrintPreviewDialog1.UseAntiAlias = true;
curPageNumber = 2;
curPageNumber_bak = 2;
}
void document_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
curPageNumber = curPageNumber_bak;
//throw new NotImplementedException();
}
private void document_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
System.Drawing.Font printFont = new System.Drawing.Font("휴먼모음T", 25, System.Drawing.FontStyle.Regular);
e.Graphics.DrawString("- " + (curPageNumber) + " -", printFont, System.Drawing.Brushes.Black, 400, 400);
if (curPageNumber == 0)
{
e.HasMorePages = false;
}
else
{
e.HasMorePages = true;
curPageNumber--;
}
}
private void button1_Click(object sender, EventArgs e)
{
PrintPreviewDialog1.Document = document;
// Call the ShowDialog method. This will trigger the document's
// PrintPage event.
PrintPreviewDialog1.ShowDialog();
}
}
ARP(주소 변환 프로토콜)은 DNS에서 논리주소를 물리주소로 변환하기 위해 사용됩니다.
변환단계는 크게 Broadcast frame으로 MAC주소로 호스트를 찾는 단계와, 해당 호스트가 Unicast frame으로 논리적인 주소인 IP를 반환시켜주는 단계로 나눌수 있습니다.
(예 : 호스트A로 호스트B의 IP를 확인하기 위한 과정)
[1단계]

[2단계]


: 해당 네트워크를 구성하는 하드웨어을 명시

: 해당 패킷이 ARP에서 어떤 역활을 하는 패킷인지를 나타냅니다.
80x86 프로세서에서는 세 종류의 메모리 주소가 있습니다.
세그먼트 구조에서 Segment Selectro + 오프셋 형식으로 나타냅니다.
기계어 명령어에서 피연산자나 명령어 주소를 지정할 때 사용되는 주소로 디버깅할때나 어셈블리에서 사용되는 주소가 이 주소입니다.
[논리 주소 예]

보통 16진수로 표기하며 0x00000000 ~ 0xffffffff 까지 지정할 수 있습니다.
[선형주소 예]

메모리의 실제주소입니다.
메모리 모델에 대해서 좀 더 자세한 설명 http://www.hanb.co.kr/network/view.html?bi_id=1321

위에 그림을 보시면 먼저 세그먼트로 나누어져 있는 메모리에 세그먼트 식별자와 오프셋값을 이용하여 찾아가면 해당 데이터의 선형 주소가 있고 그 선형 주소를 이용하여 페이징 되어 있는 메모리를 찾아가면 물리 주소가 있습니다.
세그먼테이션은 각 프로세스에 다른 선형 주소 공간을 할당하는 메모리 관리 기법입니다.
리눅스에서는 메모리 관리를 좀 더 간단하고 다른 대중적인 아키텍처와 호환하기 위해서 세그먼테이션을 매우 제한적으로 지원합니다.
세그먼트 디스크립터는 세그먼트 특징을 기술하는 8바이트 크기의 데이터입니다.
세그먼트 디스크립터는 GDT(Global Descriptor Table)이나 LDT(Local Descriptor Talbe)에 저장 되는데, GDT는 보통 하나만 정의하지만 LDT는 필요한 만큼 정의해서 사용할수 있습니다. GDT가 위치한 주소는 gdtr 프로세서 레지스터에, LDT는 lgtr 프로세서 레지스터에 들어가 있습니다.

이러한 세그먼테이션 디스크립터를 이용하여 세그먼테이션 유닛이 논리 주소를 선형 주소로 변환합니다. 세그먼테이션 유닛은 세그먼테이션를 처리하기 위한 하드웨어 적인 회로로써 다음과 같은 작업을 수행합니다.

또한 세그먼트 디스크립터로의 빠른 접근하기 위해서 80x86프로세서는 논리 주소를 선형 주소로 빠르게 변형하기 위하여 프로그래밍이 가능한 여섯개의 세그먼테이션 레지스터에 각각 프로그램이 불가능한 레지스터를 추가로 제공합니다.
세그먼트 셀렉터를 세그먼테이션 레지스터로 로딩할때마다 이 프로그래밍이 불가능한 레지스터에 세그먼트 디스크립터를 저장하여 프로세서가 GDT나 LDT에 접근하지 않고 바로 세그먼트에 접근 할 수 있도록 해줍니다.
페이징은 선형주소를 ‘페이지’라는 고정된 크기로 나누는 메모리 관리 기법입니다.
한 페이지에 있는 연속된 선형 주소는 연속된 물리 주소로 매핑되어 커널은 모든 선형 주소마다 물리 주소와 접근 권한을 지정하는 것이 아니라 페이지 단위로 지정합니다.
페이징 유닛은 램의 모든 영역이 ‘페이지 프레임’이라는 고정된 길이로 나뉘어져 있다고 생각하며, 각 페이지 프레임마다 페이지가 하나씩 들어가는 식으로 메모리를 관리합니다.
일반적으로 80x86에서는 4KB 크기의 페이지를 사용합니다.
선형 주소 변환은 ‘페이지 디렉토리’라고 하는 변환 테이블을 사용하는 단계와 ‘페이지 테이블’을 사용하는 단계로 이루어집니다. 이렇게 두 단계로 나누어 변환하는 이유는 프로세스마다 필요한 페이지 테이블이 램에서 차지하는 크기를 줄이기 때문입니다.

제어 레지스터 cr3에는 현재 사용 중인 페이지 디렉토리의 물리 주소가 들어 있습니다. 이를 좀 더 자세히 살펴 보겠습니다.
커널이 어떤 프로세스에 0x20000000에서 0x2003ffff까지 선형 주소를 할당하였고 0x20021406에 있는 값을 가져오려고 하겠습니다.
리눅스에서는 32비트와 64비트 아키텍처 양쪽 모두에 적합하도록 페이징을 3단계 걸쳐서 수행합니다. (커널 2.6.11부터는 네 단계의 페이징 모델이 채택되었습니다)

일반적인 32비트 아키텍처에서는 페이지 중간 디렉토리 필드의 길이가 0비트라고 표시하고 페이지 상위 디렉토리 및 페이지 중간 디렉토리를 기본적으로 제거합니다.
하지만 포인터 연결 과정에서 페이지 상위 디렉토리와 페이지 중간 디렉토리의 위치는 그대로 남겨놓아서 동일한 코드로 32비트와 64비트 아키텍처 모두 정상적으로 동작하게 됩니다.
물리 주소 확장 기능이 활성된 32비트 아키텍처에서는 페이지 전역 디렉토리가 80x86의 페이지 디렉토리 포인터 테이블에 해당되며, 페이지 상위 디렉토리는 제거되고 리눅스의 중간 디렉토리는 80x86의 페이지 디렉토리에, 리눅스의 페이지 테이블은 80x86의 페이지 테이블에 해당하게됩니다.
64비트 아키텍처에서는 3 또는 4 단계의 페이징이 사용됩니다.
IP 프로토콜은 오류제어에 대한 메커니즘이 포함되어 있지 않습니다.
단지 수신 주소로 패킷을 보내버릴뿐 해당 패킷이 안전하게 도착하였는지는 체크하지 못한다는 말입니다. 그렇기때문에 IP 프로토콜만으로는 올바른 데이터 전송을 할 수 없습니다. 이를 해결하기 위해 같이 사용하는 프로토콜이 바로 ICMP 프로토콜입니다.
즉, ICMP 프로토콜은 송신 호스트에게 IP 전달에 대한 다양한 메세지를 전달하기 위한 프로토콜입니다.
개념적으로는 TCP/IP 아키텍처중 Internet 계층에 속하며 IP 모듈내에 ICMP 모듈이 포함된 형태라고 보시면 됩니다.

총 8바이트의 헤더로 구성되어 있습니다.
Type에는 해당 ICMP 패킷이 어떠한 종류의 ICMP 메세지를 보내는 패킷인지 나타내는 것이고 Code에는 해당 종류의 메세지 중 세부사항 메세지를 의미하는 코드 값입니다.
Type에는 매우 많은 종류가 있는데, 그 중에 많이 사용하는 유형 몇가지만 알아볼 것입니다.
IP노드와 네트워크 간의 통신이 가능한지를 확인 하기 위해 사용됩니다. Echo Request(0)을 보내면 Echo Reply(8)이 응답하는 방식으로 동작합니다 (ex : ping 프로그램)
IP 패킷이 목적지에 제대로 전달되지 않은 경우 일반적으로 라우터에게 탐지가 되는데 이때 라우터가 출발지 호스트에게 보낼때 사용됩니다.
[Type3 코드 표]

라우터에서 받는 패킷의 전송 속도가 보내는 전송 속도보다 클 경우, 임시로 패킷을 버퍼에 임시로 저장을 하게 되는데, 버퍼가 다 차버릴 경우 그 뒤에 받는 패킷은 버릴수 밖에 없게 됩니다. 그렇기 때문에 버퍼가 다 차기 전에 어느정도 버퍼를 비워줘야 하는데 그러기 위해 라우터에게 패킷을 보내는 호스트에게 패킷을 천천히 보낼 것을 요청을 해야 합니다. 이 때 사용됩니다.
좀 더 최적에 가까운 경로가 탐지 되었을 경우 패킷을 보내는 호스트에게 이를 알림으로 패킷이 좀 더 최적의 가까운 경로로 보내질 수 있도록 유도할 때 사용됩니다.
[Type5 패킷 구조]

라우터에서 동적으로 생성되어 있는 라우터를 탐지하기 위해 사용됩니다.
[Type9 패킷 구조]

호스트에서 해당 지역에 존재하는 라우터 IP 주소를 획득하기 위해 사용됩니다.
TTL값이 0이 되어 패킷을 폐기하야 하거나 단편화된 패킷이 모두 도달하지 않아 재조립이 불가능할 때 출발지 호스트에게 이를 알리기 위해 사용됩니다.

저장매체가 없는 요청 호스트의 IP 주소를 알아내기 위해 사용됩니다.
RARP, BOOTP 또는 DHCP에서 사용할 것을 권장하고 있습니다.
[Type 15, 16 패킷 구조]

저장매체가 없는 특정 호스트가 서브넷 마스크를 획득하기 위해 사용됩니다.
[Type 17, 18 패킷 구조]


TOS : 서비스 유형
IP 패킷을 수신하는 곳에서 임의대로 이 값을 정할 수 있기때문에 요즘에는 거의 의미 없는 필드입니다. 왜냐하면 너도나도 전부 이 값을 높게 셋팅해서 보내면 전부 최우선 순위를 갖게 되기 때문에 우선순위라는 것 자체가 의미가 없어지게됩니다.
Total Length : 데이터를 포함한 전체 길이. 프레임 규격을 맞추기 위해 패딩(padding) 옵션을 사용하고자 할때 필요합니다. 패딩은 현재 프레임보다 작은 최소 프래임 규격을 갖는 네트워크에 전송하기 위해 가짜 데이터를 넣는 것입니다.



