윈도우 폰 7에서 PC와 TCP 소켓 통신을 구현하는 방법을 설명합니다. 윈도우 폰 7 에뮬레이터와 PC의 간단한 TCP 서비스 간 통신을 설정하는 방법에 대해 다룹니다.
TCP 클라이언트는 주로 소켓 연결 설정, 데이터 송수신 및 기존 소켓 종료 기능을 구현합니다.
1 using System;
2 using System.Net;
3 using System.Windows;
4 using System.Windows.Controls;
5 using System.Windows.Documents;
6 using System.Windows.Ink;
7 using System.Windows.Input;
8 using System.Windows.Media;
9 using System.Windows.Media.Animation;
10 using System.Windows.Shapes;
11
12 // 수동 추가된 네임스페이스
13 using System.Net.Sockets;
14 using System.Threading;
15 using System.Text;
16
17 namespace NetworkCommunication
18 {
19 public class TcpConnector
20 {
21 private NetworkChannel communicationSocket = null;
22
23 // 비동기 작업 완료 시 알림을 위한 이벤트 객체
24 static ManualResetEvent operationCompleted = new ManualResetEvent(false);
25
26 // 비동기 작업 시간 초한 정의. 이 시간 내에 응답을 받지 못하면 작업 중단.
27 const int OPERATION_TIMEOUT = 5000;
28
29 // 최대 수신 버퍼 크기
30 const int MAX_RECEIVE_BUFFER = 2048;
31
32 // 지정된 포트의 서버에 소켓 연결
33 // serverAddress 서버 주소
34 // portNumber 연결 포트
35 // 반환값: 연결 결과 문자열
36 public string EstablishConnection(string serverAddress, int portNumber)
37 {
38 string connectionResult = string.Empty;
39
40 // DnsEndPoint 생성. 서버 포트가 이 메서드에 전달됨
41 DnsEndPoint serverEndpoint = new DnsEndPoint(serverAddress, portNumber);
42
43 communicationSocket = new NetworkChannel(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
44
45 // 연결 요청을 위한 SocketAsyncEventArgs 객체 생성
46 SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
47 eventArgs.RemoteEndPoint = serverEndpoint;
48
49 // Completed 이벤트를 위한 인라인 이벤트 핸들러
50 // 참고: 이 이벤트 핸들러는 이 메서드를 자체적으로 포함시키기 위해 인라인으로 구현되었습니다.
51 eventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object sender, SocketAsyncEventArgs e)
52 {
53 connectionResult = e.SocketError.ToString();
54 // 요청이 완료되었음을 표시, UI 스레드 차단 안 함
55 operationCompleted.Set();
56 }
57 );
58
59 operationCompleted.Reset();
60 communicationSocket.ConnectAsync(eventArgs);
61 operationCompleted.WaitOne(OPERATION_TIMEOUT);
62
63 return connectionResult;
64 }
65
66 public string TransmitData(string data)
67 {
68 string response = "Operation Timeout";
69
70 if (communicationSocket != null)
71 {
72 // SocketAsyncEventArgs 객체 생성 및 속성 설정
73 SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
74 eventArgs.RemoteEndPoint = communicationSocket.RemoteEndPoint;
75 eventArgs.UserToken = null;
76
77 eventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object sender, SocketAsyncEventArgs e)
78 {
79 response = e.SocketError.ToString();
80 operationCompleted.Set();
81 }
82 );
83
84 // 전송할 데이터를 전송 버퍼로 설정
85 byte[] dataBuffer = Encoding.UTF8.GetBytes(data);
86 eventArgs.SetBuffer(dataBuffer, 0, dataBuffer.Length);
87
88 operationCompleted.Reset();
89 communicationSocket.SendAsync(eventArgs);
90 operationCompleted.WaitOne(OPERATION_TIMEOUT);
91 }
92 else
93 {
94 response = "Socket is not initialized";
95 }
96
97 return response;
98 }
99
100 public string ReceiveData()
101 {
102 string response = "Operation Timeout";
103
104 if (communicationSocket != null)
105 {
106 SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
107 eventArgs.RemoteEndPoint = communicationSocket.RemoteEndPoint;
108 eventArgs.SetBuffer(new Byte[MAX_RECEIVE_BUFFER], 0, MAX_RECEIVE_BUFFER);
109
110 eventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object sender, SocketAsyncEventArgs e)
111 {
112 if (e.SocketError == SocketError.Success)
113 {
114 // 수신 버퍼에서 데이터 가져오기
115 response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
116 response = response.Trim('\0');
117 }
118 else
119 {
120 response = e.SocketError.ToString();
121 }
122
123 operationCompleted.Set();
124 }
125 );
126
127 operationCompleted.Reset();
128 communicationSocket.ReceiveAsync(eventArgs);
129 operationCompleted.WaitOne(OPERATION_TIMEOUT);
130 }
131 else
132 {
133 response = "Socket is not initialized";
134 }
135
136 return response;
137 }
138
139 /// <summary>
140 /// 소켓 연결을 닫고 관련 모든 리소스를 해제합니다
141 /// </summary>
142 public void TerminateConnection()
143 {
144 if (communicationSocket != null)
145 {
146 communicationSocket.Close();
147 }
148 }
149 }
150 }
TCP 클라이언트 사용 방법은 다음과 같습니다:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Net;
5 using System.Windows;
6 using System.Windows.Controls;
7 using System.Windows.Documents;
8 using System.Windows.Input;
9 using System.Windows.Media;
10 using System.Windows.Media.Animation;
11 using System.Windows.Shapes;
12 using Microsoft.Phone.Controls;
13
14 /*
15 * 윈도우 폰 7 에뮬레이터에서 실행하여 PC와 소켓 통신을 수행할 수 있습니다. Simple TCP 서비스에서 적절한 응답을 받습니다.
16 */
17
18 namespace NetworkCommunication
19 {
20 public partial class CommunicationPage : PhoneApplicationPage
21 {
22 const int ECHO_PORT = 7; // 에코 포트: PC 시스템의 Simple TCP 서비스와 함께 사용, 수신한 문자열을 에코합니다
23 const int QOTD_PORT = 17; // 오늘의 명언 포트: PC 시스템의 Simple TCP 서비스와 함께 사용합니다
24
25 // 생성자
26 public CommunicationPage()
27 {
28 InitializeComponent();
29
30 txtServerAddress.Text = "yonghang-pc"; // 컴퓨터 이름: 바탕화면 -> 컴퓨터 속성에서 확인 가능
31 txtMessage.Text = "테스트 메시지"; // 전송할 문자열
32 }
33
34 private void btnEcho_Click(object sender, RoutedEventArgs e)
35 {
36 // 로그 초기화
37 ClearLog();
38
39 // 입력 유효성 확인
40 if (ValidateServerInput() && ValidateMessageInput())
41 {
42 // TcpConnector 인스턴스 초기화
43 TcpConnector connector = new TcpConnector();
44
45 // Echo 서버에 연결 시작
46 Log(String.Format("서버 '{0}'의 {1} 포트로 연결 중 (echo) ...", txtServerAddress.Text, ECHO_PORT), true);
47 string result = connector.EstablishConnection(txtServerAddress.Text, ECHO_PORT);
48 Log(result, false);
49
50 // Echo 서버에 문자열 전송
51 Log(String.Format("서버로 '{0}' 전송 중 ...", txtMessage.Text), true);
52 result = connector.TransmitData(txtMessage.Text);
53 Log(result, false);
54
55 // Echo 서버로부터 응답 수신
56 Log("수신 요청 중 ...", true);
57 result = connector.ReceiveData();
58 Log(result, false);
59
60 // 소켓 연결 종료
61 connector.TerminateConnection();
62 }
63
64 }
65
66 // 오늘의 명언 가져오기
67 private void btnGetQuote_Click(object sender, RoutedEventArgs e)
68 {
69 ClearLog();
70
71 if (ValidateServerInput())
72 {
73 TcpConnector connector = new TcpConnector();
74
75 Log(String.Format("서버 '{0}'의 {1} 포트로 연결 중 (오늘의 명언) ...", txtServerAddress.Text, QOTD_PORT), true);
76 string result = connector.EstablishConnection(txtServerAddress.Text, QOTD_PORT);
77 Log(result, false);
78
79 Log("수신 요청 중 ...", true);
80 result = connector.ReceiveData();
81 Log(result, false);
82
83 connector.TerminateConnection();
84 }
85 }
86
87 // 입력 확인
88 private bool ValidateMessageInput()
89 {
90 if (String.IsNullOrWhiteSpace(txtMessage.Text))
91 {
92 MessageBox.Show("전송할 문자열을 입력하세요.");
93 return false;
94 }
95
96 return true;
97 }
98
99 // 서버 입력 확인
100 private bool ValidateServerInput()
101 {
102 if (String.IsNullOrWhiteSpace(txtServerAddress.Text))
103 {
104 MessageBox.Show("서버 주소를 입력하세요!");
105 return false;
106 }
107
108 return true;
109 }
110
111 // TextBox에 테스트 정보 출력
112 private void Log(string message, bool isOutgoing)
113 {
114 string direction = (isOutgoing) ? ">> " : "<< ";
115 txtOutput.Text += Environment.NewLine + direction + message;
116 }
117
118 // 테스트 정보 초기화
119 private void ClearLog()
120 {
121 txtOutput.Text = String.Empty;
122 }
123 }
124 }