@@ -103,28 +103,97 @@ private async Task RegisterConnection(Guid userId, WebSocket socket)
103
103
await _webSocketService . ConnectAsync ( userId . ToString ( ) ) ;
104
104
}
105
105
106
- /// <summary>
107
- /// 세션 루프 실행
106
+ /// <summary>
107
+ /// 세션 루프 실행
108
108
/// </summary>
109
109
private async Task RunSessionLoop ( WebSocket socket , string userId )
110
110
{
111
- var buffer = new byte [ 1024 ] ;
111
+ var buffer = new byte [ 1024 * 4 ] ; // Increase buffer size for better performance
112
+ var cancellationTokenSource = new CancellationTokenSource ( ) ;
113
+
114
+ // Set a reasonable timeout for WebSocket operations
115
+ cancellationTokenSource . CancelAfter ( TimeSpan . FromMinutes ( 30 ) ) ;
116
+
112
117
try {
113
- while ( socket . State == WebSocketState . Open ) {
114
- var result = await socket . ReceiveAsync ( new ArraySegment < byte > ( buffer ) , CancellationToken . None ) ;
118
+ _logger . LogInformation ( "WebSocket 세션 시작: {UserId}" , userId ) ;
119
+
120
+ // Send initial connection confirmation without exposing user ID
121
+ var welcomeMessage = System . Text . Encoding . UTF8 . GetBytes ( "{\" type\" :\" connected\" ,\" status\" :\" success\" }" ) ;
122
+ await socket . SendAsync (
123
+ new ArraySegment < byte > ( welcomeMessage ) ,
124
+ WebSocketMessageType . Text ,
125
+ true ,
126
+ cancellationTokenSource . Token ) . ConfigureAwait ( false ) ;
127
+
128
+ while ( socket . State == WebSocketState . Open && ! cancellationTokenSource . Token . IsCancellationRequested )
129
+ {
130
+ WebSocketReceiveResult result ;
131
+ using var ms = new MemoryStream ( ) ;
132
+ do
133
+ {
134
+ result = await socket . ReceiveAsync ( new ArraySegment < byte > ( buffer ) , cancellationTokenSource . Token )
135
+ . ConfigureAwait ( false ) ;
136
+ if ( result . MessageType == WebSocketMessageType . Close )
137
+ {
138
+ _logger . LogInformation ( "연결 종료 요청: {UserId}" , userId ) ;
139
+ break ;
140
+ }
141
+ ms . Write ( buffer , 0 , result . Count ) ;
142
+ } while ( ! result . EndOfMessage ) ;
143
+
144
+ if ( result . MessageType == WebSocketMessageType . Close ) break ;
145
+
146
+ // WebSocket의 기본 제어 메시지들 처리
147
+ if ( result . MessageType == WebSocketMessageType . Binary ) {
148
+ _logger . LogDebug ( "Binary 메시지 받음: {UserId}" , userId ) ;
149
+ continue ;
150
+ }
115
151
116
- if ( result . MessageType == WebSocketMessageType . Close ) {
117
- _logger . LogInformation ( "연결 종료 요청: {UserId}" , userId ) ;
118
- break ;
152
+ // Handle heartbeat/ping messages
153
+ if ( result . MessageType == WebSocketMessageType . Text ) {
154
+ var message = System . Text . Encoding . UTF8 . GetString ( ms . ToArray ( ) ) ;
155
+ // 매우 단순한 ping 판별 → 추후 JSON 파싱으로 교체 권장
156
+ if ( string . Equals ( message , "ping" , StringComparison . OrdinalIgnoreCase ) ||
157
+ message . Contains ( "\" type\" :\" ping\" " , StringComparison . OrdinalIgnoreCase ) ) {
158
+ var pongMessage = System . Text . Encoding . UTF8 . GetBytes ( "{\" type\" :\" pong\" }" ) ;
159
+ await socket . SendAsync (
160
+ new ArraySegment < byte > ( pongMessage ) ,
161
+ WebSocketMessageType . Text ,
162
+ true ,
163
+ cancellationTokenSource . Token ) . ConfigureAwait ( false ) ;
164
+ }
119
165
}
120
166
}
121
167
}
168
+ catch ( OperationCanceledException ) {
169
+ _logger . LogWarning ( "WebSocket 세션 타임아웃: {UserId}" , userId ) ;
170
+ }
171
+ catch ( WebSocketException ex ) {
172
+ _logger . LogWarning ( ex , "WebSocket 연결 오류: {UserId}" , userId ) ;
173
+ }
122
174
catch ( Exception ex ) {
123
- _logger . LogError ( ex , "세션 루프 오류: {UserId}" , userId ) ;
175
+ _logger . LogError ( ex , "세션 루프 예상치 못한 오류: {UserId}" , userId ) ;
124
176
}
125
177
finally {
126
- _logger . LogInformation ( "연결 해제: {UserId}" , userId ) ;
127
- await _webSocketService . DisconnectAsync ( userId ) ;
178
+ _logger . LogInformation ( "WebSocket 연결 해제: {UserId}" , userId ) ;
179
+
180
+ try {
181
+ await _webSocketService . DisconnectAsync ( userId ) . ConfigureAwait ( false ) ;
182
+ _connectionRegistry . Unregister ( userId ) ;
183
+
184
+ if ( socket . State == WebSocketState . Open || socket . State == WebSocketState . CloseReceived ) {
185
+ await socket . CloseAsync (
186
+ WebSocketCloseStatus . NormalClosure ,
187
+ "Connection closed" ,
188
+ CancellationToken . None ) . ConfigureAwait ( false ) ;
189
+ }
190
+ }
191
+ catch ( Exception ex ) {
192
+ _logger . LogError ( ex , "WebSocket 정리 중 오류: {UserId}" , userId ) ;
193
+ }
194
+ finally {
195
+ cancellationTokenSource ? . Dispose ( ) ;
196
+ }
128
197
}
129
198
}
130
199
}
0 commit comments