컴퓨터네트워크 TCP/IP Socket Programming
강의내용 : TCP/IP Socket 프로그래밍 지난날의대학교컴퓨터네트워크과목은대부분프로그래밍실습이없이 이론적인분석과추상적인기술을다루는과목이었다. 간혹교과서에프로그램코드가소개되기도하지만그것은실습을위한 것이라기보다는설명을돕기위한것에불과한경우가많았다. 오늘날인터넷의발달로일상생활속에서네트워크를접하게되었고수천만대의컴퓨터들이인터넷을통해서서로연결되어있다. 이제이런인터넷환경에서의프로그래밍기술이컴퓨터관련학과학생들에게필수적인조건이되었다. 이런이유로이교과목에서는이론적인내용을최소화하고주로 TCP/IP Socket 인터페이스를사용한네트워크프로그래밍실습을주된 내용으로다룬다.
용어정의 Computer Network: Communication Channel( 통신채널 ) 을통하여서로연결되어있는 Machine( 통신장치 ) 들의집합통신장치는주로 Host, Router 들을일컷는다. Communication Channel: 정보를포함하고있는일련의바이트 (sequence of bytes) 들을이동시키는매체. Ethernet, dial-up Modem 등. Host: Application( 응용프로그램 ) 이실행되고있는사용자컴퓨터, 혹은서버컴퓨터. 컴퓨터네트워크의끝단에있는장치. Router: 하나의 Communication Channel 에서다른 Channel 로정보를중계, 전달하는장치이다. Router 도소프트웨어가실행되고는있지만그런소프트웨어는응용프로그램이라고볼수는없다. 세상의모든호스트들을직접연결하는것은실질적으로불가능하므로소그룹의호스트들을 Router 를통하여그룹간에연결하는방식은오늘날의인터넷을구성하는핵심장치이다. 호스트에서실행되는응용프로그램은 Router 와직접연결되는일은없으므로응용프로그램을개발하는입장에서는 Router 의존재를몰라도상관없다.
용어정의 Packet: 프로그램에의해서만들어진정보를포함하는일련의 Byte 들을컴퓨터네트워크의환경에서는 Packet 이라고부른다. Packet 에는응용프로그램이생성한 User Data( 사용자데이터 ) 와각프로토콜계층을통과하면서추가되는 Control Data( 콘트롤데이터 ) 들로이루어져있다. User Data: 응용프로그램간에전달되는정보. 이정보는네트워크의양끝에있는 Host 의응용프로그램간에만의미를갖는다. 그이외에의장소즉, Packet 이경유하는 Router, Channel 등에서는단순히 Payload 일뿐이다. Control Data: 목적지주소 (IP 주소 ), 에러복구를위한코드등 packet 을정확히전달하기위해서필요한데이터. Payload: 각프로토콜계층에서책임지고전달해야할일련의바이트들로이루어진전달대상물 Protocol: 통신프로그램간에 Packet 을교환하기위한규약 ( 약속 ). Packet 의구조의정의 ( 예 : 목적지주소의위치및길이 ) 및 Encoding 방법등 Host 간에 packet 을교환하기위해서해결되어야할모든기술적인약속의통칭이다. 통신상에발생하는문제들의분야별로프로토콜그룹을계층화한다. TCP/IP 는그런프로토콜계층중의중요한부분을담당하고있으며흔히 Internet Protocol 이라고부른다. TCP/IP 의주요계층은 Transport 계층과 Network 계층이다.
용어정의 Network 계층 (Layer): Packet 을목적지에정확히신속히보내기위한경로설정과관련된기능을수행하는계층으로서이를위하여 TCP/IP suit 에서는 IP(Internet Protocol) 포로토콜을제공한다. IP(Internet Protocol): 호스트와호스트가마치하나의채널로연결된것처럼보이게 ( 느껴지게 ) 하기위하여두호스트간에존재하는채널과라우터를선택하는기능 ( 경로설정 ) 을수행한다. IP 프코토콜은 Datagram 서비스를제공하는 Best-Effort 프로토콜이다. Datagram: IP 프로토콜간에교환되는 packet 으로서각각의 Packet 마다주소를기록하여각자의경로를통하여전공된다. 같은그룹을이루는 packet 이다른경로를통하여전달될수도있기때문에나중에보낸 Packet 이먼저보낸 packet 보다먼저 Host 에도착할수도있다. Best-Effort 서비스 : 최선을다하여데이터를전송하지만물리적인환경의제약에의해데이터의손실이나, 중복등이발생할수있는전송서비스.
용어정의 Transport 계층 (Layer): Host 와 Host(End-to-End: 단대단 ) 간의 Packet 교환을담당하는계층으로서 TCP/IP suit 에서는 TCP, UDP 두프로토콜을제공한다. 호스트와호스트간의신뢰성있는데이터교환을위하여혼잡제어, 데이터버퍼관리등의기능을수행하는계층이다. TCP(Transfer Control Protocol): Connection Oriented( 연결기반 ) 프로토콜로서 TCP 는 IP 계층의기능상발생가능한에러 ( 데이터손실, 중복등 ) 를감독하고보완하는기능을수행한다. TCP 포로토콜이 Host 간의신뢰성있는 Byte_Stream 을보장하기때문에그위에있는응용프로그램은이문제로부터자유로워질수가있다. UDP(User Datagram Protocol): TCP 와는달리연결을설정하지않으며에러처리도하지않는프로토콜로서 Best-Effort 서비스를 Host 가아닌응용프로그램까지연장한형태의프로토콜이다. 따라서, UDP 서비스를사용하는응용프로그램은자체적으로에러처리 ( 데이터손실, 중복데이터등의처리 ) 를해야한다. Connection Oriented 프로토콜 : 데이터의전송을시작하기전에미리두프로그램간에 Handshake Message 의교환을통한연결설정작업이필요한전송방법. 두프로그램간에연결이됐다는것은두프로그램이서로의존재를인식하고데이터를주고받기위한준비를마치고서로를기대하는상태가됨을의미한다. Hand-Shake: 두프로그램간에서로의주소를교환하고한번에처리할수있는데이터의크기등을교환하여원활한통신을하기위한상대방의정보를주고받는절차
호스트 호스트 어플리케이션 어플리케이션 소켓 소켓 트랜스포트계층 TC P U D P 라우터 TC P U D P 트랜스포트계층 네트워크계층 IP 채널 IP 채널 IP 네트워크계층
용어정의 Address( 주소 ): 편지를보낼때봉투에주소를정해진위치에정해진규칙에의하여기재하듯이또한, 전화를할때먼저상대방의전화번호를정확히입력하여야하듯이인터넷상에서데이터를교환하려면데이터의목적지에해당하는주소가있어야한다. TCP/IP suit 에의하여사용되는주소로는 IP Address 라고불리우는 Internet Address 와 TCP/UDP 가응용프로그램을구별하기위하여사용하는 Port 번호두가지가있다. IP 주소 : IP 주소는인터넷상에서통신장비 ( 호스트포함 ) 를구별해내기위한값으로서주로부호없는정수가사용된다. 통신장비는통신채널에연결되어있기때문에 IP 주소는통신장비와직접연결된채널의주소라고도볼수있다. 따라서, Router 와같이하나이상의채널에연결된장비는 IP 주소도하나이상을가지고있다. IP 주소는두개의버전이있는데현재많이사용되는 IPv4(IP version 4) 과 IPv6(IP version 6) 이있다. IPv4: 4 바이트 (32bits) 크기의부호없는정수로서사람이읽기편하도록한바이트씩끊어서 4 개의숫자로나타낸다 ( 숫자사이에점을찍어서문자열처럼표시한다 ). ( 예 : 220.123.79.10). 각숫자는 0 부터 255 사이의값이다. 할당할수있는전체 IP 주소의개수는 232 로서 42 억여개의통신장비에주소를지정할수있다. IPv6: IPv4 로서필요한 IP 주소를모두할당하기에는부족을느끼게되어길이를늘린형태의 IP 주소. 16 바이트 (128bits) 길이의정수로서 IPv4 보다훨씬많은개수의통신장비에주소를부여할수있다 (2128 개 ).
용어정의 Port 번호 : IP 주소는 Host 의주소 (Host 가연결된 Channel 의주소 ) 이다. 따라서 IP 주소를사용하여해당 Host 까지데이터를전달하는것이가능하다. Host 에도착한데이터는그데이터를사용할응용프로그램에게전달되어야한다. 그러나하나의 Host( 컴퓨터 ) 에서 Socket 을사용하여실행되고있는응용프로그램이여러개있을수있다. 이런경우 Host 에서실행되고있는응용프로그램을서로구별하기위하여또하나의주소가필요하다. 이목적을위하여사용하는것이 Port 번호이다. Port번호는 16bit의부호없는정수로서 1부터 65535까지의값이사용된다. 그중일부는일반적으로많이사용되는응용프로그램그룹에할당되어있는숫자가있다. 예를들면 21번포트는 FTP, 80번포트는 HTTP에할당되었기때문에일반적인목적으로사용되는포트는이런잘알려진포트 (Well Known Port) 의값을사용하지않아야한다. Socket: Socket 은응용프로그램이 TCP/IP 의존재를인식하지않고상대방응용프로그램에접근하여마치파일에서데이터를쓰고읽는것처럼인터넷을사용할수있게해주는개념적인통신 API 이다. 응용프로그램에의하여 Socket 에 Write 된데이터는다른호스트의응용프로그램에의하여 Read 된다.
용어정의 Domain name: 숫자로나타내는 IP 주소는사람이기억하기어려운단점이있다. 그보다더심각한문제로는같은통신장비의 IP 주소가바뀔수가있다는점이다. 예를들면홈페이지서버의 IP 주소가 211.225.30.99 이었다가어느날네트워크구성을다시하는과정에서 220.123.79.11 로바뀌었다고가정하자. 그렇게되면 IP 주소가바뀐것을모르는사람은계속 211.225.30.99 를사용하게되고결국연결이되지않을것이다. 이런문제를해결하기위하여 IP 주소를직접사용하지않고 IP 주소에의미있는단어로구성된이름을할당하는방법을사용한다. 이른 Domain Name 이라고한다. 예를들어서 211.225.30.99 의 Domain name 은 cse.konyang.ac.kr 을사용한다. 이정보는 Domain Name Server 에의하여관리가된다. 만약 IP 주소가바뀐다하여도 Domain Name Server 의테이블만수정하면우리는계속하여 cse.konyang.ac.kr 를사용할수있는것이다. Domain name 은계층적으로구성하여 IP 주소가할당된통신장비의인터넷상에서의소속정보도제공한다. cse.konyang.ac.kr 은그이름에서대한민국의대학교육기관중의하나인건양대학교의 cse 라는이니셜을사용하는서버라는것을알수있다.
용어정의 Server and Client: 전화통화를할때언제나먼저전화를거는사람이있고그전화를받는사람이있게된다. 인터넷통신도마찬가지로통신을먼저요청하는개체가있고그요청을받아서응답하는개체로성격이나뉘어진다. 여기서먼저통신을요청하는개체를 Client( 고객 ) 이라고하고, 통신요청을기다리고있다가요청에응답하는개체를 Server( 서버 ) 라고한다. Server 는누가통신을요청할지모르는상태에서기다리고있게되지만, Client 는자신이통신하려는상대방을정확히알고있어야한다. 이러한특성때문에 Server 와 Client 프로그램은코딩상에서서로다른구조를가지고있다.
컴퓨터네트워크 Socket Programming
Domain Name 으로 IP 주소알아내기 Client 가 Server 에연결하기위하여서는서버의 IP 주소와 Port 번호를알고있어야한다. IP 주소대신 Domain Name 을사용하는경우에는 Domain Name Server(DNS) 를통하여해당 Name 에 Mapping 된 IP 주소를알아내야한다..NET 에서는통하여 DNS 의정보를얻기위하여 Dns 클래스를제공한다. Dns 클래스 Dns 클래스는호스트이름이나 IP 주소에대하여 Domain Name Server 가가지고있는정보를제공하기위하여몇몇개의 static 메소드를제공한다. Dns 클래스메소드 public static IPHostEntry GetHostByAddress(IPAddress address); IPAddress 객체를전달받아서해당호스트의 DNS 정보가들어있는 IPHostEntry 객체를 return 한다. (AugmentNullException, SocketException, SecurityException 이발생할수있다.) public static IPHostEntry GetHostByAddress(string dotaddress); dotted-quad 문자열 IP 주소를전달받아서 DNS 정보가들어있는 IPHostEntry 객체를 return 한다. (AugmentNullException, SocketException, FormatException 이발생할수있다.) public static IPHostEntry GetHostByName(string hostname); 컴퓨터의도메인이름을전달받아서 DNS 정보가들어있는 IPHostEntry 객체를 return 한다. (AugmentNullException, SocketException, FormatException 이발생할수있다.) public static IPHostEntry GetHostByName(string hostname); 컴퓨터의도메인이름을전달받아서 DNS 정보가들어있는 IPHostEntry 객체를 return 한다. (AugmentNullException, SocketException, FormatException 이발생할수있다.) public static string GetHostName( ); Local 호스트의이름을문자열로 return.
IPAddress 클래스 IP 네트워크의주소정보를포함하고있다. IPAddress 클래스메소드 public IPAddress(long address); 생성자생성자함수로서부호없는 4 바이트의정수값을전달받아서 IP 주소정보가들어있는 IPAddress 객체를 return public static short HostToNetworkOrder(short); short 정수의바이트순서를네크워크의순서로수정 public static int HostToNetworkOrder(int); public static long HostToNetworkOrder(long); public static short NetworkToHostOrder(short); short 정수의바이트순서를호스트의순서에맞게 public static int NetworkToHostOrder(int); public static long NetworkToHostOrder(long); public static IPAddress Parse(string dotaddress); dotted-quad 타입의 IP 주소를받아서 IPAddress 객체를 return IPAddress Fields public static readonly IPAddress Any; Any network 인터페이를의미하는 0.0.0.0 의주소. public static readonly IPAddress Broadcast Subnet 의모든호스트를의미하는 255.255.255.255 의주소 public static readonly IPAddress Loopback Local 호스트를 127.0.0.1 의주소
IPHostEntry 클래스 Dns 클래스의 GetHostByName(), GetHostByAddress(), Resolve() 메소드가 Return 하는 Container 클래스로서 DNS 의정보를담고있다. IPHostEntry 클래스프로퍼티 public IPAddress[] AddressList { get; set; IPAddress 객체들의배열 public string[] Aliases { get; set; 별칭문자열배열 public string HostName { get; set; 호스트의정식이름 (Canonical Name)
아래의프로그램코드는 Dns 클래스의 static 메소드를사용하여 IP 주소를알아내는예제프로그램이다. 아래의코드를복사하여실행해보라프로젝트명 : IPAddressIinfo, 파일명 : IPAddressInfo.cs using System; // Console 클래스, String 타입등의 ns using System.Net; //Dns, IPHostEntry, IPAddress 를위한 ns using System.Net.Sockets; // Socket 을위한 ns namespace cse13.ipaddressinfo { class IPAddressInfo { static void Main(string[] args) { string localhostname; try { localhostname = Dns.GetHostName(); catch (Exception e) { Console.WriteLine(" 호스트를찾을수없습니다.\n" + e.message); return; //catch Console.WriteLine("Local 호스트정보 :"); PrintHostInfoByName(localHostName); PrintHostInfoByName("www.google.com"); //Main() //---------------------------------------------------- static void PrintHostInfoByName(String host) { IPHostEntry hostinfo; try { //hostinfo = Dns.GetHostEntry(host); //hostinfo = Dns.Resolve(host); hostinfo = Dns.GetHostByName(host); catch (Exception e) { Console.WriteLine(" 호스트를찾을수없습니다 : " + host + " " + e.message); return; Console.WriteLine(" 정식이름 : \n\t" + hostinfo.hostname); Console.WriteLine("IP 주소 : "); foreach(ipaddress ipaddr in hostinfo.addresslist) { Console.WriteLine("\tdotted-quad: {0 10진수 :({1) 16진수 :({1:X)", ipaddr.tostring(), ipaddr.address); Console.WriteLine("------------------------------------"); //PrintHostInfoByName() //class IPAddressInfo //ns
Server and Client.NET 에서는 Winsock Socket 를좀더쉽게사용할있도록하기위한 Wrapper 로서다음의세개의 High Level 소켓을제공한다. 서버소켓 : TcpListener, 클라이언트소켓 : TcpClient, UdpClient 다음의예제는 TcpListener, 를사용하는사용하는간단한서버프로그램이다. 이서버는클라이언트로부터전달받은데이터를다시클라이언트에게돌려보낸다. using System; using System.IO; using System.Text; using System.Net; using System.Net.Sockets; namespace pjkim.tcpechoserver { class TCPEchoServer { static void Main() { // 버퍼크기 const int BUFSIZE = 100; TcpListenerServer // 포트번호 int portnumber = 9999; //Client 로부터전송되는데이터를받기위한버퍼 byte[] rcvbuffer = new byte[bufsize]; // 전달받은총 byte 수 int bytesrcvd; // 서버소켓 TcpListener server = null; //Client 소켓 TcpClient client = null; // 데이터 Stream NetworkStream netstream = null; //----------------------------------------------------- //Client 의연결요청을기다리기위하여 TcpListener 를생성하여실행 (Start) try { server = new TcpListener(IPAddress.Any, portnumber); server.start(); catch (SocketException e) { Console.WriteLine(e.ErrorCode + ": " + e.message); Environment.Exit(e.ErrorCode); 다음페이지에계속
앞페이지의뒤에붙여넣으세요 for (; ; ) { client = null; netstream = null; try { client = server.accepttcpclient(); netstream = client.getstream(); Console.WriteLine("Client 를처리하고있습니다..."); //Client 가연결을종료할때까지모든바이트를받음 //(Client 가연결을끊으면 return 값이 0 가됨 ) int totalbytesechoed = 0; while ((bytesrcvd = netstream.read(rcvbuffer, 0, rcvbuffer.length)) > 0) { netstream.write(rcvbuffer, 0, bytesrcvd); totalbytesechoed += bytesrcvd; //for Console.WriteLine("echoed {0 bytes.", totalbytesechoed); //Client 소켓과 Stream을닫음 netstream.close(); client.close(); catch (Exception e) { Console.WriteLine(e.Message); netstream.close(); //for(;;) //Main() //class TCPEchoServer //namespace
아래의프로그램은 Client 프로그램의예이다. 아래의프로그램은서버에연결하여일련의메시지를전송한후서버로부터되돌아오는데이터를받아서출력한다. using System; using System.IO; using System.Text; using System.Net; using System.Net.Sockets; namespace pjkim.tcpechoclient { class TCPEchoClient { static void Main() { string serveraddr = IPAddress.Loopback.ToString(); int portnumber = 9999; TcpClient string msg = "Hello 컴퓨터 Network"; byte[] bytebuffer = Encoding.Unicode.GetBytes(msg); TcpClient client = null; NetworkStream netstream = null; try { client = new TcpClient(serverAddr, portnumber); Console.WriteLine(" 서버에연결되었습니다... 메시지를보냅니다. \n 보내는메시지 : {0", msg); netstream = client.getstream(); //Encode 된메시지를전송 netstream.write(bytebuffer, 0, bytebuffer.length); Console.WriteLine("{0 바이트를서버에보냈습니다...\n", bytebuffer.length); // 서버로부터되돌아오는메시지를수신 int totalbytesrcvd = 0; int bytesrcvd = 0; while(totalbytesrcvd < bytebuffer.length) { if( (bytesrcvd = netstream.read(bytebuffer, totalbytesrcvd, bytebuffer.length - totalbytesrcvd)) == 0) { Console.WriteLine(" 연결이예기치않게종료되었습니다."); break; totalbytesrcvd += bytesrcvd; //while Console.WriteLine(" 서버로부터 {0 바이트를받았습니다. \n받은메시지 : {1", totalbytesrcvd, Encoding.Unicode.GetString(byteBUffer, 0, totalbytesrcvd)); catch(exception e) { Console.WriteLine(e.Message); finally { if (netstream!= null) netstream.close(); if(client!= null) client.close(); //Main() //class TCPEchoClient //namespace
프로그램설명 (TcpListenerServer) 참조파일은서버나클라이언트모두 System 하나만필요함. 1 행 ~ 30 행대부분의.NET 클래스가정의된 namespace IPAddress 클래스가정의된 namespace TcpListener, TcpClient 클래스가정의된 namespace 상수정수 100 포트번호 9999 길이 100byte 의 byte 배열선언 ( 데이터수신용 ) 서버가연결요청을처리하기위한소켓 reference 선언 연결된클라이언트를위한소켓서버는이소켓을통해서클라이언트와대화 클라이언트와데이터를주고받기위한스트림객체 reference. 연결된클라이언트로부터얻음.
프로그램설명 (TcpListenerServer) 31 행 ~ 40 행 TcpListener 객체생성 로컬단자에서연결요청대기시작. 서버소켓을생성하고연결요청을받는일을시작한다 (Start) TcpListener객체의생성자에 IPAddress.Any 주소 (0.0.0.0) 와포트번호를전달한다. 포터번호를부여할때이미사용중인포트번호를중복하여지정하지않도록주의해야한다. 포트번호가중복되면 SocketException 예외가발생함. IPAddress.Any는 0.0.0.0 번지로서로칼인터페이스로들어오는모든주소를받아들인다. 42 행 ~ 72 행 Client 로부터연결요청이들어오기를기다리다가연결요청이오면연결을하고연결된클라이언트의 Socket 을 return 연결된 Client 와데이터를주고받을수있는 Stream 객체를얻는다. Stream 객체와 Client Socket 을닫는다 Client 로부터 byte stream 을받는다. 데이터는여러조각으로나뉘어서올수있으므로받은 byte 수가 0 이될때까지바복해서버퍼에받는다. 받은데이터는바로상대방에게보낸다. 상대방 Client 가연결을종료하면 Read 함수는 0 을 return 47 행의 AcceptTcpClient() 함수는클라이언트가연결을요청할때까지 Return 되지않고 Block 된상태로있다가연결요청이오면상대방과대화를위한 Socket 을생성하여 return 한다. 48 행의 GetStream 은연결될클라이언트와 byte stream 을주고받을수있는 NetworkStream 객체를 return.
프로그램설명 (TcpClient) 1 행 ~5 행.NET classes IOException Encoding IPAddress class Sockets 11 행 ~22 행 서버가클라이언트와같은컴퓨터에서실행되므로서버의주소는 Loopback(127.0.0.1) 으로지정 연결하려는서버의 port 번호 서버로송신할메시지 String 객체메시지는 Byte 배열로 Encoding 해야함 ( 한글이있으므로 Unicode) 18 행 : TCP socket 은일련의바이트 (sequences of bytes) 를주고받으므로 string 객체의문자열은 Byte 배열로전환되어야한다.
프로그램설명 (TcpClient) 11 행 ~22 행 클라이언트 Socket 객체생성함과동시에서버에연결 ( 생성자에서버의 IP 주소와 Port 번호를전달 ) 연결된 Socket 에서 NetworkStream 객체를얻음 ( 데이터송수신용 ) NeworkSteam 객체를사용하여서버에데이터전송 보낸메시지의길이만큼의 byte 를받을때까지 while 문안에서반복하여 Read. 만약받은데이터의길이가 0 인경우에는상대방과연결이끊어진것임. 송수신이성공했던실패했던마지막엔스트림과 Socket 을닫음. 31 행 : netstream.write(bytebuffer, 0, bytebuffer.length); 는 bytebuffer 에있는데이터를보내는데보내는데이터의시작위치는 0 번위치이고보내는양은길이 bytebuffer.length 만큼전송한다. ( 명령어는모든데이터를한번에보내는것처럼보이지만실제하부에서전달될때는작은덩어리로나누어서전달될수있다. 39 행 ~47 행 : 상대방이보내는데이터가한번에오지않을수있기때문에 while 문안에서원하는양의데이트를모두받을때까지반복하여수신한다. 만약기대하는만큼의데이터가도착하지않은상태에서 Read 함수가 0 을 return 하면그것은연결이비정상적으로종료된것으로생각할수있다.
TcpClient 클래스 TcpClient 는 TCP 프로토콜을사용하여쉽게상대방에연결하고데이터를주고받을수있는기능을제공하는클래스이다. 생성자 : public TcpClient(); public TcpClient(IPEndPoint localep); public TcpClient(string hostname, int port); TcpClient 생성자는위와같이세종류가있는데두번째생성자의경우는 IPEndPoint 에상대방의 IP 주소와 Port 번호정보가들어있다. 마지막생성자는호스트이름 /IP 주소, Port 번호가따로주어진다. 첫번째생성자처럼연결을위한정보가주어지지않은경우에는객체생성후사용하기전에반드기 Connect() 함수를호출하여직접연결을하여야한다. Methods: public void Close(); TCP 연결을종료한다. public void Connect(IPEndPoint); public void Connect(IPAddress address, int port); public void Connect(string hostname, int port); 위의생성자에서첫번째생성자를사용하여아직연결이되어있지않은경우에여기의세개의 Connect() 함수를사용하여연결을할수있다. ArgumentNullException, ArgumentOutOfRangeException, SocketException, ObjectDisposedException 등이발생할수있다. public NetworkStream GetStream(); NetworkStream 객체를 return 한다. InvalidOperationException, ObjectDisposedException
IPEndPoint 클래스 IPEndPoint 는 IP 주소와 Port 번호의쌍으로이루어진네트워크의종단의정보를갖고있다. 생성자 : public IPEndPoint(long address, int port); public IPEndPoint(IPAddress address, int port); 두개의생성자가있고각각망의종단점의정보를 argument 로받아들인다. Method: public virtual string ToString(); IPEndPoint 객체가가지고있는주소를문자열형태로 return 한다. 프로퍼티 : public IPAddress Address {get; set; 종단점의 IP 주소를가지고있는 IPAddress 객체 public int Port {get; set; 종단점의포트번호를가지고있는정수를가져오거나지정.
TcpListener 클래스 TcpListener 클라이언트의연결요청을관리하고요청을받아들이는등의기능을수행하는서버측 TCP 관리객체이다. 생성자 : public TcpListener(int port); public TcpListener(IPEndPoint localep); public TcpListener(IPAddress address, int port); 세개의생성자가있으나 port 번호만사용하는첫번째생성자는더이상사용되지않는다. Method: public Socket AcceptSocket(); 기다리고있는연결요청을받아서연결하고연결된 Socket 을 return. 이 Socket 을사용하여데이터를 send, receive 한다. public TcpClient AcceptClient(); 기다리고있는연결요청을받아서연결하고연결된 TcpClient 를 return. 이객체가제공하는 NetworkStream 을사용하여데이터를 read, write. public bool Pending(); 기다리고있는연결요청이있으면 true 를 return. Otherwise.. public void Start(); TcpListener 가내포하고있는 Socket 을초기화하고, Listen 을시작. public void Stop(); Listen 을종료하고 TcpListener 를닫는다. Accept 된 TcpClient 객체나, Socket 객체는개별적으로 close 해야함.
NetworkStream 클래스 Stream 은.NET 이제공하는추상화된기본적인 I/O 방식이다. Stream 은연속으로늘어선 Byte 들의흐름으로생각할수있다. 연결이완료된 TcpClient 객체는 NetworkStream 객체를가지고있어서이 Stream 객체를사용하여데이터를보내거나 (write), 가져온다 (read). Method: public virtual void Close(); NetworkStream 객체를닫는다. public abstract int Read(byte[] buffer, int offset, int len); len 만큼의 Byte 를읽어서 Buffer 의앞에서부터 offset 만큼떨어진위치에서부터 len 만큼의장소에집어넣는다. public abstract void Write(byte[] buffer, int offset, int len); buffer 의앞에서부터 offset 만큼떨어지위치에서부터시작해서길이 len 만큼의 byte 를전송한다. 프로퍼티 : public virtual bool DataAvailable {get; Stream 에읽을데이터가있으면 true 를 return 한다.
.NET Socket 클래스 앞에서사용한 TcpListener, TcpClient 클래스들은 Socket객체를쉽게사용할수있도록제공되는 Wrapper 클래스이다. 이클래스들을사용하면코딩도간결하고쉽지만아무래도기능면에서는어느정도제한이있다. 따라서, 간단함프로그램이아니라면 Socket클래스의객체를직접사용해야할경우도있을것이다. 여기서는앞에서코딩했던 TcpEchoServer, TcpEchoClient를 Socket 객체를직접사용하는방법으로다시작성하였다. 다음의서버, 클라이언트프로그램의코드를복사하여실행해보라. TcpSocketServer using System; using System.Net; using System.Net.Sockets; namespace pjkim.tcpechoserversocket { class TcpEchoServerSocket { const int BUFSIZE = 100; // 데이터받는버퍼크기 const int BACKLOG = 5; // 연결요청을기다리는큐의길이 static void Main() { int servport = 9999; Socket server = null; try { server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); server.bind(new IPEndPoint(IPAddress.Any, servport)); server.listen(backlog); catch(socketexception e) { Console.WriteLine(e.ErrorCode + ": " + e.message); Environment.Exit(e.ErrorCode); //catch byte[] rcvbuffer = new byte[bufsize]; int bytesrcvd; 다음페이지에계속
앞페이지의코드뒤에붙여넣으세요 for(;;) { Socket client = null; try { client = server.accept(); Console.WriteLine("{0 의 Client 가연결되었습니다.", client.remoteendpoint); int totalbytesechoed = 0; while((bytesrcvd = client.receive(rcvbuffer, 0, rcvbuffer.length, SocketFlags.None)) > 0 ) { client.send(rcvbuffer, 0, bytesrcvd, SocketFlags.None); totalbytesechoed += bytesrcvd; //while Console.WriteLine("{0 바이트를받아서전송했습니다.", totalbytesechoed); client.close(); catch(exception e) { Console.WriteLine(e.Message); if(client!= null) client.close(); //Main(); //class TcpEchoServerSocket //ns