/// <summary> /// todo:검토중... /// 원격 서버에 접속 성공 했을 때 호출됩니다. /// </summary> /// <param name="socket"></param> public void on_connect_completed(Socket socket, CUserToken token) { // SocketAsyncEventArgsPool에서 빼오지 않고 그때 그때 할당해서 사용한다. // 풀은 서버에서 클라이언트와의 통신용으로만 쓰려고 만든것이기 때문이다. // 클라이언트 입장에서 서버와 통신을 할 때는 접속한 서버당 두개의 EventArgs만 있으면 되기 때문에 그냥 new해서 쓴다. // 서버간 연결에서도 마찬가지이다. // 풀링처리를 하려면 c->s로 가는 별도의 풀을 만들어서 써야 한다. SocketAsyncEventArgs receive_event_arg = new SocketAsyncEventArgs(); receive_event_arg.Completed += new EventHandler <SocketAsyncEventArgs>(receive_completed); receive_event_arg.UserToken = token; receive_event_arg.SetBuffer(new byte[1024], 0, 1024); SocketAsyncEventArgs send_event_arg = new SocketAsyncEventArgs(); send_event_arg.Completed += new EventHandler <SocketAsyncEventArgs>(send_completed); send_event_arg.UserToken = token; send_event_arg.SetBuffer(null, 0, 0); begin_receive(socket, receive_event_arg, send_event_arg); }
void OnConnectAsync(object _sender, SocketAsyncEventArgs _connectArgs) { Console.WriteLine(this + " OnConnectAsync"); if (_connectArgs.SocketError == SocketError.Success) { Console.WriteLine(" > Socket Connect Success > Connect completd!"); CUserToken _token = new CUserToken(); // 데이터 수신 준비. networkService.OnConnectCompleted(client, _token); if (onConnected != null) { onConnected(_token); } } else { // failed. Console.WriteLine(string.Format("Failed to connect. {0}", _connectArgs.SocketError)); } }
void on_connect_completed(object sender, SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) { //Console.WriteLine("Connect completd!"); CUserToken token = new CUserToken(); // 데이터 수신 준비. this.network_service.on_connect_completed(this.client, token); if (this.connected_callback != null) { this.connected_callback(token); } } else { // failed. Console.WriteLine(string.Format("Failed to connect. {0}", e.SocketError)); } }
// This method is invoked when an asynchronous receive operation completes. // If the remote host closed the connection, then the socket is closed. // private void process_receive(SocketAsyncEventArgs e) { // check if the remote host closed the connection CUserToken token = e.UserToken as CUserToken; if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { token.on_receive(e.Buffer, e.Offset, e.BytesTransferred); bool pending = token.socket.ReceiveAsync(e); if (!pending) { // Oh! stack overflow?? process_receive(e); } } else { Console.WriteLine(string.Format("error {0}, transferred {1}", e.SocketError, e.BytesTransferred)); close_clientsocket(token); } }
private void process_receive(SocketAsyncEventArgs e) { CUserToken token = e.UserToken as CUserToken; if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { // 이후의 작업은 CUserToken에 맡긴다. token.on_receive(e.Buffer, e.Offset, e.BytesTransferred); // 패킷 덩어리 만듭니다. // 다음 메시지 수신을 위해서 다시 Rece_Async 매소드 호출 bool pending = token.socket.ReceiveAsync(e); if (!pending) { process_receive(e); } } else { Console.WriteLine(string.Format("error {0}, transferred {1}", e.SocketError, e.BytesTransferred)); close_clientsocket(token); } }
/// <summary> /// 새로운 클라이언트가 접속 성공 했을 때 호출됩니다. /// AcceptAsync의 콜백 매소드에서 호출되며 여러 스레드에서 동시에 호출될 수 있기 때문에 공유자원에 접근할 때는 주의해야 합니다. /// </summary> /// <param name="_clientSocket"></param> void OnAcceptProcess(Socket _clientSocket, object _token) { Console.WriteLine(this + " OnAcceptProcess(신규유저가 접속됨(콜백받음))\r\n > _newClientSocket:{0}\r\n > token:{1}", _clientSocket, _token); //todo: // peer list처리. Interlocked.Increment(ref this.connectedCount); //Interlocked 클래스는 int 형 값을 증가시키거나 감소시키는데 사용한다. //멀티 쓰레드 환경에서 하나의 int 형 전역 변수를 공유한다고 생각해보자. //이런 경우에 A 쓰레드와 B 쓰레드가 값을 동시에 읽어와서 //B 쓰레드가 수정한 값을 저장하고, //A 쓰레드가 다시 수정한 값을 저장하게 되면 //B 쓰레드의 변경사항을 잃어버리게 된다. Console.WriteLine(" > connectedCount:{0} ThreadID:{1} _newClientSocket.Handle:{2}", this.connectedCount, Thread.CurrentThread.ManagedThreadId, _clientSocket.Handle); // 플에서 하나 꺼내와 사용한다. SocketAsyncEventArgs _argsReceive = this.receiveArgsPool.Pop(); SocketAsyncEventArgs _argsSend = this.sendArgsPool.Pop(); CUserToken _userToken = null; Console.WriteLine(" > argsReceive, argsSend -> 스택에서 뺴서"); if (this.onSessionCreated != null) { Console.WriteLine(" > 서버세션(UserToken) 리스트에 등록"); _userToken = _argsReceive.UserToken as CUserToken; this.onSessionCreated(_userToken); } Console.WriteLine(" > 연결 : UserTokent(_newClientSocket, _argsReceive, _argsSend)"); ReceiveWaitBegin(_clientSocket, _argsReceive, _argsSend); //user_token.start_keepalive(); }
/// <summary> /// AcceptAsync의 콜백 매소드 /// </summary> /// <param name="_sender"></param> /// <param name="_acceptArgs">AcceptAsync 매소드 호출시 사용된 EventArgs</param> void OnAcceptCallback(object _sender, SocketAsyncEventArgs _acceptArgs) { Console.WriteLine(this + " OnAcceptAsync (신규유저접속시도)\r\n -> _sender:{0}\r\n -> _acceptArgs:{1}", _sender, _acceptArgs); if (_acceptArgs.SocketError == SocketError.Success) { Console.WriteLine(" -> NewClient Success"); // 접속에 따른 OS가 받아온 Socket를 SocketAsynEvnetArgs에 실어서 보내줌. // 새로 생긴 소켓을 보관해 놓은뒤~ Socket _clientSocket = _acceptArgs.AcceptSocket; CUserToken _token = _acceptArgs.UserToken as CUserToken; // 다음 연결을 받아들인다. this.autoResetEvent.Set(); // 이 클래스에서는 accept까지의 역할만 수행하고 클라이언트의 접속 이후의 처리는 // 외부로 넘기기 위해서 콜백 매소드를 호출해 주도록 합니다. // 이유는 소켓 처리부와 컨텐츠 구현부를 분리하기 위함입니다. // 컨텐츠 구현부분은 자주 바뀔 가능성이 있지만, 소켓 Accept부분은 상대적으로 변경이 적은 부분이기 때문에 // 양쪽을 분리시켜주는것이 좋습니다. // 또한 클래스 설계 방침에 따라 Listen에 관련된 코드만 존재하도록 하기 위한 이유도 있습니다. if (this.onAcceptNewClient != null) { this.onAcceptNewClient(_clientSocket, _token); } return; } else { Console.WriteLine(" -> NewClient Fail"); //todo:Accept 실패 처리. //Console.WriteLine("Failed to accept client."); } // 다음 연결을 받아들인다. this.autoResetEvent.Set(); }
// This method is called whenever a receive or send operation is completed on a socket // // <param name="e">SocketAsyncEventArg associated with the completed send operation</param> void send_completed(object sender, SocketAsyncEventArgs e) { CUserToken token = e.UserToken as CUserToken; token.process_send(e); }
public CHeartbeatSender(CUserToken server, uint interval) { this.server = server; this.interval = interval; this.timer_heartbeat = new Timer(this.on_timer, null, Timeout.Infinite, this.interval * 1000); }