티스토리 뷰
프로토콜을 짤 때 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;}}
'프로그래밍 > 잡탕' 카테고리의 다른 글
[Web] 오늘의 삽질 - require.js 관련 (0) | 2016.03.09 |
---|---|
Flask에서 response에 유니코드가 있을 때의 문제 해결 (0) | 2015.07.02 |
Eclipse에서 Jess 쓰기 (0) | 2015.05.14 |
[Octave] Gradient Descent Multi feature (0) | 2015.04.18 |
[AWS] Elastic Beanstalk로 Flask 프로젝트 Deploy 하기 (0) | 2015.04.09 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday