티스토리 뷰

반응형
----------------------

Server Socket 작성 하기

----------------------

1. 소스 코드를 작성 하기 전에 우선 전체적인 코드를 개략적으로 이해 하기로 하자 .

   우선 서버의 입장에서 로컬 종점을 생성 한다 .

   리스닝을 위한 소켓을 열기 전에 로컬 종점 주소를 작성 해야 하며 서비스에 대한 종점을 생성 하기 위해 호스트의 IP 주소와

   서비스의 포트 번호를 조합하여 TCP/IP 서비스의 고유 주소를 정의 한다 .

   Dns 클래스는 로컬네트워크 기기에서 지원하는 네트워크 주소에 대한 정보를 되돌려 주는 메소드를 제공 한다 .

   로컬 네트워크 기기가 하나 이상의 네트워크 주소를 가지거나 로컬 시스템이 하나 이상의 네트워크 기기를 지원 한다면

   Dns 클래스는 모든 네트워크 주소에 대한 정보를 되돌려 주며 애플리케이션은 아 배열에서 적절한 주소를 선택해야 한다.

 

    // 소켓에 사용할 종점을 설정

    IPHostEntry ipHost     = DNS.Resolve(“localhost”);

    IPAddress   ipAddr     = ipHost.AddressList[0];

    IPEndPoint  ipEndPoint = new IPEndPoint(ipAddr, 11000);

2. 다음은 Socket 클래스의 새로운 인스턴스를 이용하여 스트림소켓을 생성 한다 . 이미 리스닝에 사용 할 로컬 종점을 작성

   하였으므로 바로 소켓을 생성 할 수 있다 .

    //TCP/IP 소켓을 생성

    Socket sListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

 

    AddressFamily 열거형은 Socket 인스턴스가 주소를 해석 하기 위해 사용하는 주소 스키마를 나타낸다.

    몇가지 값들은 아래와 같다

      --------------------------------------------------

    AddressFamily.InterNetwork        : IP 버전 4 주소

    AddressFamily.InterNetwork V6     : IP 버전 6 주소

    AddressFamily.Ipx                 : IPX/SPX 주소

    AddressFamily.NetBios             : NetBios 주소

      --------------------------------------------------

   SocketType 은 TCP 와 UDP 소켓을 구분 하는데 이용 가능한 값은 아래와 같다.

      --------------------------------------------------------------------------------------------------------------------

   SocketType.Dgram : 데이터그램을 지원, Dgram 은 Udp ProtocolType 과 AddressFamily.InterNetwork와 함께 사용되어야 한다.

   SocketType.Raw : Raw Socket

   SocketType.Stream : 스트림 소켓 지원 , Stream 은 Tcp ProtocolType 과 AddressFamily.InterNetwork와 함께 사용되어야 한다

      --------------------------------------------------------------------------------------------------------------------

   세번째 파라미터 , 네번째 파라미터는 소켓에 필요한 프로토콜 형식을 정의 한다 . 그 값은 아래와 같다 .

    ------------------------

    Raw : Raw 패킷 프로토콜

    Tcp : TCP

    Udp : UDP

    Ip  : Internet Protocol

    ------------------------

 

  다음 단계는 Bind() 메소드를 사용하여 소켓에 이름을 부여 한다 . 생성자를 이용하여 소켓을 개방하면

  소켓에 아무런 이름도 할당되어 있지 않다 . 즉 Bind() 메소드를 통해 소켓을 Local 종점에 연결 시키는 것이다 .

  try {

            sListener.Bind(ipEndPoint);

 

 

  이제 소켓이 생성 되었고 , 이름이 바인딩 되었으므로 Listen() 을 사용하여 들어오는 연결에 대해 리스닝을 수행 할 수 있다 .   이때 파라미터에는 큐에 대기중인 연결의 최대 개수를 지정 한다 .

            sListener.Listen(10);

 

  위에서 리스닝을 했으므로 이젠 Accept() 를 이용하여 클라이언트의 연결을 수신하여 클라이언트와 서버의 이름 연결을 완료   한다 . Accept() 메소드는 대기중인 요청 큐로 부터 먼저 들어온 연결을 가지고 와 이를 처리할 새로운 소켓을 생성 한다.

  새로운 소켓이 생성 되었다고 하더라도 원래 소켓은 계속 리스닝을 수행 하므로 복수의 클라이언트 요청을 처리하기 위해서는   멀티쓰레드를 사용 한다 .

            while(true) {

                                ...

                                Socket handler = sListener.Accept();

 

  Send(), Receive() 메소드를 이용하여 데이터를 보내고, 받는다.

                                string data = null;

                                while(true) {

                                    byte[] bytes = new byte[1024];

                                    // 클라이언트로부터 수신된 데이터

                                    int byteRes = handler.Receive(byte);

 

                                    // 바이트를 문자열로 변환

                                    data += Encoding.Default.GetString(bytes, 0, byteRec);

                                    // 메시지의 끝인지 확인

                                    if (data.IndexOf(“”) > -1) {

                                        break;

                                    }

                                }

 

  루프를 빠져 나온 후 클라이언트에게 응답을 돌려주기 위해 새로운 바이트 배열을 준비 한다.

  변환을 마친 후 Send() 메소드를 이용하여 데이터를 보내자

 

                                string theReply = “Thank you for those ” + data.Length.ToString() + “ characters …”;

                                byte[] msg = Encoding.Default.GetBytes(theReply);

                                handler.Send();

  서버와 클라이언트의 데이터 교환이 끝나면 Close() 를 이용하여 소켓을 종료 한다.

  항상 Close() 를 하기 전에 Shutdown() 을 이용하여 남아 있는 데이터를 확실히 제거 하자.

  각 소켓 인스턴스 마다 Close() 메소드를 호출 해야 한다 .

 

                                handler.Shutdown(SocketShutdown.Both);

                                handler.Close();

  SocketShutdown 값은 열거형으로 아래와 같은 값을 취한다 .

    ----------------------------

    Both : 송 . 수신용 소켓 모두

    Receive : 수신용

    Send : 송신용 소켓

    ----------------------------

 

    소스 코드는 아래와 같다 .[SocketServer.cs]

===========================================================================================================================

using System;

using System.Net.Sockets;

using System.Net;

using System.Text;

public class SocketServer

{

    public static void Main (string [] args)

    {

        // establish the local end point for the socket

        IPHostEntry ipHost = Dns.Resolve("localhost");

        IPAddress ipAddr = ipHost.AddressList[0];

        IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

        // create a Tcp/Ip Socket

        Socket sListener = new Socket(AddressFamily.InterNetwork,

        SocketType.Stream, ProtocolType.Tcp);

        // bind the socket to the local endpoint and

        // listen to the incoming sockets

        try

        {

            sListener.Bind(ipEndPoint);

            sListener.Listen(10);

            // Start listening for connections

            while (true)

            {

                Console.WriteLine("Waiting for a connection on port {0}",ipEndPoint);

 

                // program is suspended while waiting for an incoming connection

                Socket handler = sListener.Accept();

                string data = null;

                // we got the client attempting to connect

                while(true)

                {

                    byte[] bytes = new byte[1024];

                    int bytesRec = handler.Receive(bytes);

                    data += Encoding.ASCII.GetString(bytes,0,bytesRec);

                    if (data.IndexOf("") > -1)

                    {

                        break;

                    }

                }

                // show the data on the console

                Console.WriteLine("Text Received: {0}",data);

                string theReply = "Thank you for those " + data.Length.ToString() + " characters...";

                byte[] msg = Encoding.ASCII.GetBytes(theReply);

                handler.Send(msg);

                handler.Shutdown(SocketShutdown.Both);

                handler.Close();

            }

        }

        catch(Exception e)

        {

            Console.WriteLine(e.ToString());

        }

    } // end of Main

}

===========================================================================================================================

 

----------------------

Client Socket 작성 하기

----------------------

1. 클라이언트 코드가 서버와 다른 점은 Connect() 메소드 부분이다.

   이것은 클라이언트가 원격의 서버에 연결 하고자 할 때 사용하는 메소드 이다.

   사용하기 위해서는 우선 원격 종점을 설정 해야 한다 .

 

    // 소켓에 사용할 원격 종점을 설정

    IPHostEntry ipHost = DNS.Resolve(“127.0.0.1”);

    IPAddress ipAddr = ipHost.AddressList[0];

    IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

    Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    sender.Connect(ipEndPoint);

 

   Connect() 메소드로 소켓을 종점 파라미터로 지정된 원격 호스트와 연결을 맺는다 .

   일단 연결이 이루어 지면 데이터를 보내고 받을 수 있다 .

 

    string theMessage = “This is a test”;

    byte[] msg = Encoding.Default.GetBytes(theMessage+””);

 

    // 소켓을 이용하여 데이터를 보냄

    int bytesSend = sender.Send(msg);

   

    // 원격으로부터 ( 서버 ) 응답을 수신

    int bytesRec = sender.Receive(bytes);

   

 

   이젠 마지막으로 Shutdown() 을 호출하여 소켓을 해제 한다 . 그리고 Close() 하자

    sender.Shutdown(SocketShutdown.Both);

    sender.Close();

 

[ 아래는 SocketClient.cs 의 소스 파일 이다 .]

===========================================================================================================================

using System;

using System.Net.Sockets;

using System.Net;

using System.Text;

public class SocketClient

{

    // If you specify any text as a command-line argument, it will be sent to the server.

    // e.g. SocketClient "Send this text" will send that string

    // If no command-line arguments are specified, a default string is sent

    public static void Main (string [] args)

    {

        // data buffer for incoming data

        byte[] bytes = new byte[1024];

 

        // connect to a Remote device

        try

        {

            // Establish the remote end point for the socket

            IPHostEntry ipHost = Dns.Resolve("127.0.0.1");

            IPAddress ipAddr = ipHost.AddressList[0];

            IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

            Socket sender = new Socket(AddressFamily.InterNetwork,

            SocketType.Stream, ProtocolType.Tcp);

            // Connect the socket to the remote endpoint. Catch any errors

            sender.Connect(ipEndPoint);

            Console.WriteLine("Socket connected to {0}",

            sender.RemoteEndPoint.ToString());

            //string theMessage=Console.ReadLine();

            string theMessage;

 

            if (args.Length==0)

                theMessage = "This is a test";

            else

                theMessage = args[0];

            byte[] msg = Encoding.ASCII.GetBytes(theMessage+"");

            // Send the data through the socket

            int bytesSent = sender.Send(msg);

            // Receive the response from the remote device

            int bytesRec = sender.Receive(bytes);

            Console.WriteLine("The Server says : {0}",

            Encoding.ASCII.GetString(bytes,0, bytesRec));

            // Release the socket

            sender.Shutdown(SocketShutdown.Both);

            sender.Close();

        }

        catch(Exception e)

        {

            Console.WriteLine("Exception: {0}", e.ToString());

        }

    }

}

===========================================================================================================================

https://tistory1.daumcdn.net/tistory/87291/skin/images/blank.png

https://tistory1.daumcdn.net/tistory/87291/skin/images/blank.png


반응형
댓글