티스토리 뷰

프로토콜을 짤 때 CRLF 단위로 메세지를 구별하기로 했어서 StreamReader.ReadLine 메소드로 메세지 읽는걸 처리했었다. 인터넷에 검색하다보니까 통짜로 소스 올라와 있던게 있길래 조금 개량해서 썼다. 


근데 이게 문제점이 NetworkStream에 메세지가 2개 이상이 왔을 때 발생했다. 동기 방식으로 구현했다보니 읽을 데이터가 있을 때만 ReadLine 메소드를 호출하게 해야해서 NetworkStream.DataAvailable로 ReadLine 메소드를 호출할 때를 확인했다. 그런데 ReadLine 메소드를 호출하면 NetworkStream에 있는 데이터를 일단 StreamReader에 가져와버려서 한 번에 여러개의 메세지가 와 있을 때 ReadLine 메소드 한 번으로 모든 메세지를 읽어버리는 문제가 발생한 것이다

따라서 더 처리해줘야 할 메세지가 남아있음에도 불구하고 DataAvailable가 호출되지 않아서 메세지큐에 메세지를 쌓질 못했다.


해결 방법으로는 ReadLine 메소드를 쓰지 않는 것으로 했다. 그리고 직접 버퍼 단위로 읽어들여서 라인처리를 해줬다. 그냥 소스를 보는게 훨 나을 것이다.

예외 체크 같은건 아직 되지 않은 상태이다. 지금 일단 급한게 있어서 -_-;;




using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.IO;
using System;
using System.Collections.Generic;
using System.Text;
 
public class SocketWrapper : MonoBehaviour
{
private static SocketWrapper instance;
private static GameObject container;
 
public static SocketWrapper Instance
{
get {
if (!instance) {
container = new GameObject ();
container.name = "SocketWrapper";
instance = container.AddComponent (typeof(SocketWrapper)) as SocketWrapper;
DontDestroyOnLoad(container);
Application.runInBackground = true;
}
 
return instance;
}
}
TcpClient mySocket;
NetworkStream theStream;
StreamWriter theWriter;
StreamReader theReader;
String Host = "127.0.0.1";
Int32 Port = 10101;
internal Boolean socketReady = false;
StringBuilder stringBuilder;
char[] buffer;
 
public LinkedList<string> messageQueue {
get;
private set;
}
 
public Action onMessageReceived {
get;
set;
}
 
public bool loggingRead {
get;
set;
}
 
void Awake ()
{
stringBuilder = new StringBuilder ();
buffer = new char[1024];
messageQueue = new LinkedList<string> ();
SetUpSocket ();
}
 
void Update ()
{
if (socketReady && theStream.DataAvailable) {
ReadSocket ();
}
 
if (stringBuilder.Length > 0) {
string content = stringBuilder.ToString();
int index = content.IndexOf("\r\n");
if( index != -1 ) {
string line = content.Substring(0, index);
if( line.Length > 0 ) {
messageQueue.AddLast(line);
if( loggingRead ) {
print (line.Length + "\n" + line);
}
}
 
stringBuilder = new StringBuilder(content.Substring(index + 2));
}
}
 
int count = messageQueue.Count;
for (int i = 0; i < count; i ++) {
if( onMessageReceived != null ) {
onMessageReceived();
}
}
}
 
public string Pop() {
string first = messageQueue.First.Value;
messageQueue.RemoveFirst ();
return first;
}
 
void SetUpSocket ()
{
try {
mySocket = new TcpClient (Host, Port);
theStream = mySocket.GetStream ();
theWriter = new StreamWriter (theStream);
theReader = new StreamReader (theStream);
socketReady = true;
Debug.Log("Socket connected");
} catch (Exception e) {
Debug.LogError ("Socket error: " + e);
}
}
 
public void WriteSocket (string theLine)
{
if (!socketReady) {
return;
}
 
string foo = theLine + "\r\n";
theWriter.Write (foo);
theWriter.Flush ();
}
 
public void ReadSocket ()
{
if (!socketReady) {
return;
}
 
if (theStream.DataAvailable) {
Array.Clear(buffer, 0, buffer.Length);
int readBytes = theReader.Read(buffer, 0, buffer.Length);
if( readBytes > 0 ) {
stringBuilder.Append(new string(buffer, 0, readBytes));
}
}
}
 
public void CloseSocket ()
{
if (!socketReady) {
return;
}
 
theWriter.Close ();
theReader.Close ();
mySocket.Close ();
socketReady = false;
}
}




댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday