11using ProjectVG . Common . Models . Session ;
2+ using System . Buffers ;
23using System . Text ;
34using System . Net . WebSockets ;
45
@@ -9,6 +10,9 @@ namespace ProjectVG.Infrastructure.Realtime.WebSocketConnection
910 /// </summary>
1011 public class WebSocketClientConnection : IClientConnection
1112 {
13+ private static readonly ArrayPool < byte > _arrayPool = ArrayPool < byte > . Shared ;
14+ private static readonly Encoding _utf8Encoding = Encoding . UTF8 ;
15+
1216 public string UserId { get ; set ; } = string . Empty ;
1317 public DateTime ConnectedAt { get ; set ; } = DateTime . UtcNow ;
1418 public System . Net . WebSockets . WebSocket WebSocket { get ; set ; } = null ! ;
@@ -21,20 +25,61 @@ public WebSocketClientConnection(string userId, WebSocket socket)
2125 }
2226
2327 /// <summary>
24- /// 텍스트 메시지를 전송합니다
28+ /// 텍스트 메시지를 전송합니다 (ArrayPool 사용으로 LOH 할당 방지)
2529 /// </summary>
26- public Task SendTextAsync ( string message )
30+ public async Task SendTextAsync ( string message )
2731 {
28- var buffer = Encoding . UTF8 . GetBytes ( message ) ;
29- return WebSocket . SendAsync ( new ArraySegment < byte > ( buffer ) , System . Net . WebSockets . WebSocketMessageType . Text , true , CancellationToken . None ) ;
32+ byte [ ] ? rentedBuffer = null ;
33+ try
34+ {
35+ // UTF8 인코딩에 필요한 최대 바이트 수 계산
36+ var maxByteCount = _utf8Encoding . GetMaxByteCount ( message . Length ) ;
37+ rentedBuffer = _arrayPool . Rent ( maxByteCount ) ;
38+
39+ // 실제 인코딩된 바이트 수
40+ var actualByteCount = _utf8Encoding . GetBytes ( message , 0 , message . Length , rentedBuffer , 0 ) ;
41+
42+ // ArraySegment 생성하여 실제 사용된 부분만 전송
43+ var segment = new ArraySegment < byte > ( rentedBuffer , 0 , actualByteCount ) ;
44+ await WebSocket . SendAsync ( segment , WebSocketMessageType . Text , true , CancellationToken . None ) ;
45+ }
46+ finally
47+ {
48+ if ( rentedBuffer != null )
49+ {
50+ _arrayPool . Return ( rentedBuffer ) ;
51+ }
52+ }
3053 }
3154
3255 /// <summary>
3356 /// 바이너리 메시지를 전송합니다
3457 /// </summary>
3558 public Task SendBinaryAsync ( byte [ ] data )
3659 {
37- return WebSocket . SendAsync ( new ArraySegment < byte > ( data ) , System . Net . WebSockets . WebSocketMessageType . Binary , true , CancellationToken . None ) ;
60+ return WebSocket . SendAsync ( new ArraySegment < byte > ( data ) , WebSocketMessageType . Binary , true , CancellationToken . None ) ;
61+ }
62+
63+ /// <summary>
64+ /// 청크 방식으로 대용량 바이너리 데이터를 전송합니다 (LOH 방지)
65+ /// </summary>
66+ public async Task SendLargeBinaryAsync ( byte [ ] data )
67+ {
68+ const int chunkSize = 32768 ; // 32KB 청크
69+ var totalLength = data . Length ;
70+ var offset = 0 ;
71+
72+ while ( offset < totalLength )
73+ {
74+ var remainingBytes = totalLength - offset ;
75+ var currentChunkSize = Math . Min ( chunkSize , remainingBytes ) ;
76+ var isLastChunk = offset + currentChunkSize >= totalLength ;
77+
78+ var segment = new ArraySegment < byte > ( data , offset , currentChunkSize ) ;
79+ await WebSocket . SendAsync ( segment , WebSocketMessageType . Binary , isLastChunk , CancellationToken . None ) ;
80+
81+ offset += currentChunkSize ;
82+ }
3883 }
3984 }
4085}
0 commit comments