[Network 09. 27]03. Chapter3 TCP

2010. 9. 26. 18:34Network

TCP는 Transmission Control Protocol의 약자로 연결 지향형 소켓이다.
연결지향형 소켓이란 통신을 하기위해 접속을 성립해야 하며 하위계층의 IP가 신뢰성을 보장하지 않는 패킷 교환 기술을 사용하기 때문이다. 접속을 하기 위해 Three way handshake를 통한 접속을 한다.
Three way handshake를 통한 접속이란?

첫째 클라이언트는 동기화플래그(SYN)을 1로 설정 시퀸스 번호 필드에 랜덤번호를 채운 TCP세그먼트를 서버로 보내 접속 요청을 개시 한다.
둘째 서버는 클라이언트로부터 받은 세그먼트의 SYN을 검사한 후 SYN와 ACK 플래그를 1로 설정, 확인응답번호 필드에 클라이언트가 보낸 시퀸스 번호에서 1만큼 증가시킨다 번호를 넣고, 시퀸스 번호는 랜덤으로 채워 클라이언트에게 응답세그먼트를 보낸다. 셋째 클라이언트는 다시 서버가 보낸 응답 세그먼트의 시퀸스 번호에서 1만큼 증가시킨 번호를 확인응답번호 필드에 넣고 ACK플래그를 1로 설정하여 서버로 응답하여 접속을 성립한다.

이 TCP의 세그먼트 헤더포맷을 보면
다음과 같은 구조를 가진다. 오류를 확인하기 위해 체크섬이 있으며 이 체크섬이 있으므로서 안전하게 파일이 도착하게 되는것이다.

TCP의 경우 서버의 리스닝소켓은 접속 성립 시에 새로운 소켓을 생성하기 때문에 접속이 성립된 후에도 리스닝 상태에 남아있게 되는 특서을 가진다. 그 흐름을 순서도로 그리면 다음과 같은 순서도가 된다.

 클라이언트의 경우는 Three way handshake를 통해 서버로의 접속을시도 하며 그후 접속요청이 수락되면 서버는 클라이언트의 통신을 위한 새로운 소켓을 생성한다.

TcpListener 클래스
   리스닝시작과 관련된 메소드
       -puclic void Start() : TcpListener 객체를 리스닝 상태로 만들고 접속 요청을 수락할 준비를 한다.
       -public void Start(int) : 인자의 접속 요청이 대기 할 수 있는 최대 큐의 길이를 의미한다.
   접속 수락과 관련된 메소드
       -public TcpClient AcceptTcpClient() : Socket 클래스의 Accept()메서드의 비슷하다. 
                                                             Accept()가 Socket객체를 반환하는 것과는 달리 TcpClient형으로 반환

   리스닝 중지
       -public void Stop()

TcpClient 클래스
   TcpClient클래스 생성자
       -public TcpClient()
       -public TcpClient(AddressFamily) :  다른 주소 스키마를 사용할 때 열거형인 AddressFamily값을 인자로 받을때 사용
       -public TcpClient(IPEndPoint) :
       -public TcpClient(string, int) : 생성자는 문자열에 아이피 주소 정수형은 포트번호가 들어간다.

NetwrokStream 클래스
   -public NetworkStream GetStream() : TcpClient 클래스의 GetStream() 메소드는 접속이 성립된 후 데이터의 송수신을 위한 NetworkStream 객체를 반환 

   데이터 송수신 메소드
       -public override int Read(byte[], int, int) : 메서드를 읽을때 사용되며 반환되는 정수형은 데이터의 바이트수를 반환한다.
       -public override void Write(byte[], int, int) : 전송하기위해 버퍼에 쓰는데 사용된다.
               byte[] : 데이터를 저장하거나 가져오기위한 배열
               int : 첫번째 인트의경우 버퍼에서 읽기 쓰기를 시작할 위치를 지정
               int : 읽기 쓰기를 수행할 최대 데이터의 길이

 이전에 소켓으로 짜보았던 에코 프로그램을 Tcp버전으로 바꿔 보면 좀더 빠른 이해를 할 것 같아. 다른 프로그램소스도 있지만 에코를 선택하여 작성한다.

1. 에코 서버
첫째, 여기도 클래스를 사용하기 위해 using 으로 Socket을 가져온다.
 using System.Net.Sockets;

둘째, 사용될 클래스의 객체를 생성해준다.
 TcpListener listener=new TcpListener(IPAddress.Any,8888);
 listener.Start();
 TcpClient client=listener.AcceptTcpClient();
 NetworkStream stream=client.GetStream();
일단 처음에는 TcpListener 서버측에서 리스너를 하나 만들어준다. 이전에 소켓에서 서버측 소켓을 만드는 방법과 똑같이 만들어 준다. 그 후 리스너를 시작하고 접속할 메시지를 받기위해 TcpClient클래스를 이용해 client라는 객체를 만들고 그 객체는 리스너에서 클라이언트가 수락한 값이 들어간다. 마지막으로 NetworkStream 클래스로 경로를 유지하기 위해 client.Stream()의 값을 넣어준다. 그럼 전반적인 Tcp사용준비가 끝난것이 된다. 

셋째, 메시지를 받고 다시 되돌려주기 위한 부분을 작성한다.
 byte[] buffer=new byte[256];
 int byteRecv=0;
 string msg="";
 while(!msg.Equals("EXIT"))
{
       byteRecv=stram.Read(buffer,0,buffer.Length);
       msg=Encoding.ASCII.GetString(buffer,0,byteRecv);
       Console.WriteLine("Client>"+msg);
       stream.Write(data,0,data.Length);
}

넷째, 사용을 마치면 스트림을 끊고 클라이언트의 관계도 접속을 마치고 리스너도 중지시킨다.
 stream.Close();
 client.Close();
 listener.Stop();

2. 에코 클라이언트

역시 소켓과 마찬가지로 Tcp또한 별반 다를게 없다.다른점만 적는다면
 TcpClient client=new TcpClient("127.0.0.1",8888);
 NetworkStream stream=client.GetStream();

접속할 서버의 위치를 TcpClient로 아이피 주소와 포트번호를 입력하고 그 것을 연결을 해주기 위해 client.GetStream연결해준다.
혹시나 서버가 열려 있지 않거나 하면 오류로 팅겨져 버린다.
 while(!msg.Equals("Exit"))
{
     do{
          Console.Write("Message>");
          msg=Console.ReadLine();
     }while(message.Length<1)
     byte[] data=Encoding.ASCII.GetBytes(msg);
     stream.Write(data,0,data.Length);
     byteRecv=steam.Read(buffer,0,buffer.Length);
     msg=Encoding.ASCII.GetString(buffer,0,byteRecv);
     Console.WriteLine("Server>"+msg);

여기서 Socket와 Tcp를 비교하면 다음과 같다.
 내용  Socket   Tcp 
 읽기  클라이언트소켓.Receive(data);  스트림.Read(buffer,0,buffer.Length);
 쓰기  클라이언트소켓.Send(data,data.length,SocketFlags.None)  스트림.Write(data,0,data.Length);