📄 socket.cs
字号:
/* * Socket.cs - Implementation of the "System.Net.Sockets.Socket" class. * * Copyright (C) 2003 Southern Storm Software, Pty Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */namespace System.Net.Sockets{using Platform;using System;using System.Collections;using System.Security;using System.Threading;public class Socket : IDisposable{ // Internal state. private IntPtr handle; private AddressFamily family; private SocketType socketType; private ProtocolType protocol; private bool blocking; private bool connected; private EndPoint localEP; private EndPoint remoteEP; private Object readLock; // Invalid socket handle. private static readonly IntPtr InvalidHandle = SocketMethods.GetInvalidHandle(); // Constructor. public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) { // Validate the parameters. if(addressFamily == AddressFamily.Unspecified) { addressFamily = AddressFamily.InterNetwork; } else if(!SocketMethods.AddressFamilySupported ((int)addressFamily)) { throw new SocketException(Errno.EINVAL); } if(socketType == SocketType.Stream) { if(protocolType == ProtocolType.Unspecified) { if(addressFamily == AddressFamily.InterNetwork || addressFamily == AddressFamily.InterNetworkV6) { protocolType = ProtocolType.Tcp; } } else if(protocolType != ProtocolType.Tcp) { throw new SocketException(Errno.EPROTONOSUPPORT); } } else if(socketType == SocketType.Dgram) { if(protocolType == ProtocolType.Unspecified) { if(addressFamily == AddressFamily.InterNetwork || addressFamily == AddressFamily.InterNetworkV6) { protocolType = ProtocolType.Udp; } } else if(protocolType != ProtocolType.Udp) { throw new SocketException(Errno.EPROTONOSUPPORT); } } else { throw new SocketException(Errno.ESOCKTNOSUPPORT); } // Initialize the local state. this.handle = InvalidHandle; this.family = addressFamily; this.socketType = socketType; this.protocol = protocolType; this.blocking = true; this.connected = false; this.localEP = null; this.remoteEP = null; this.readLock = new Object(); // Attempt to create the socket. This may bail out for // some address families, even if "AddressFamilySupported" // returned true. This can happen, for example, if the user // space definitions are available for IrDA, but the kernel // drivers are not. "AddressFamilySupported" may not be // able to detect the kernel capabilities on all platforms. if(!SocketMethods.Create((int)addressFamily, (int)socketType, (int)protocolType, out handle)) { throw new SocketException(SocketMethods.GetErrno()); } } private Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, IntPtr handle, bool blocking, EndPoint remoteEP) { // Set up for a new socket that has just been accepted. this.handle = handle; this.family = addressFamily; this.socketType = socketType; this.protocol = protocolType; this.blocking = blocking; this.connected = true; this.localEP = null; this.remoteEP = remoteEP; this.readLock = new Object(); } // Destructor. ~Socket() { Dispose(false); } // Implement the IDisposable interface. void IDisposable.Dispose() { Dispose(true); GC.SuppressFinalize(this); } // Accept an incoming connection on this socket. public Socket Accept() { IntPtr currentHandle; IntPtr newHandle; EndPoint remoteEP; // Get the socket handle, synchronized against "Close". lock(this) { // Bail out if the socket has been closed. if(handle == InvalidHandle) { throw new ObjectDisposedException (S._("Exception_Disposed")); } currentHandle = handle; } // Create the sockaddr buffer from the local end point. byte[] addrReturn = LocalEndPoint.Serialize().Array; Array.Clear(addrReturn, 0, addrReturn.Length); // Accept a new connection on the socket. We do this outside // of the lock's protection so that multiple threads can // wait for incoming connections on the same socket. if(!SocketMethods.Accept (currentHandle, addrReturn, out newHandle)) { throw new SocketException(SocketMethods.GetErrno()); } // Create the end-point object for the remote side. remoteEP = LocalEndPoint.Create(new SocketAddress(addrReturn)); // Create and return a new socket object. return new Socket(family, socketType, protocol, newHandle, blocking, remoteEP); } // Asynchronous operation types. private enum AsyncOperation { Accept, Connect, Receive, ReceiveFrom, Send, SendTo }; // enum AsyncOperation // Asynchronous operation control class. private sealed class AsyncControl : IAsyncResult { // Internal state. private WaitHandle waitHandle; private bool completedSynchronously; private bool completed; private AsyncOperation operation; private AsyncCallback callback; private Object state; private Socket socket; private byte[] buffer; private int offset; private int count; private SocketFlags flags; public int result; public Socket acceptResult; public EndPoint remoteEP; private Exception exception; // Constructor. public AsyncControl(AsyncCallback callback, Object state, Socket socket, byte[] buffer, int offset, int count, SocketFlags flags, EndPoint remoteEP, AsyncOperation operation) { #if ECMA_COMPAT this.waitHandle = SocketMethods.CreateManualResetEvent(); #else this.waitHandle = new ManualResetEvent(false); #endif this.completedSynchronously = false; this.completed = false; this.operation = operation; this.callback = callback; this.state = state; this.socket = socket; this.buffer = buffer; this.offset = offset; this.count = count; this.flags = flags; this.result = -1; this.acceptResult = null; this.remoteEP = remoteEP; this.exception = null; } // Run the operation thread. private void Run(IAsyncResult state) { try { switch(operation) { case AsyncOperation.Accept: { acceptResult = socket.Accept(); } break; case AsyncOperation.Connect: { socket.Connect(remoteEP); } break; case AsyncOperation.Receive: { result = socket.Receive (buffer, offset, count, flags); } break; case AsyncOperation.ReceiveFrom: { result = socket.ReceiveFrom (buffer, offset, count, flags, ref remoteEP); } break; case AsyncOperation.Send: { result = socket.Send (buffer, offset, count, flags); } break; case AsyncOperation.SendTo: { result = socket.SendTo (buffer, offset, count, flags, remoteEP); } break; } } catch(Exception e) { // Save the exception to be thrown in EndXXX. exception = e; } completed = true; if(callback != null) { callback(this); } if(waitHandle != null) { #if ECMA_COMPAT SocketMethods.WaitHandleSet(waitHandle); #else ((ManualResetEvent)waitHandle).Set(); #endif } } // Start the async thread, or perform the operation synchronously. public void Start() { if(SocketMethods.CanStartThreads()) { SocketMethods.QueueCompletionItem (new AsyncCallback(Run), this); } else { completedSynchronously = true; Run(null); } } // Wait for an asynchronous operation to complete. // Also handles exceptions that were thrown by the operation. public void Wait(Socket check, AsyncOperation oper) { if(socket != check || operation != oper) { throw new ArgumentException(S._("Arg_InvalidAsync")); } WaitHandle handle = waitHandle; if(handle != null) { if(!completed) { handle.WaitOne(); } ((IDisposable)handle).Dispose(); } waitHandle = null; if(exception != null) { throw exception; } } // Implement the IAsyncResult interface. public Object AsyncState { get { return state; } } public WaitHandle AsyncWaitHandle { get { return waitHandle; } } public bool CompletedSynchronously { get { return completedSynchronously; } } public bool IsCompleted { get { return completed; } } }; // class AsyncControl // Begin an asynchronous operation to accept an incoming connection. public IAsyncResult BeginAccept(AsyncCallback callback, Object state) { // Create the result object. AsyncControl async = new AsyncControl (callback, state, this, null, 0, 0, SocketFlags.None, null, AsyncOperation.Accept); // Start the background process. async.Start(); return async; } // End an asynchronous accept operation. public Socket EndAccept(IAsyncResult asyncResult) { if(asyncResult == null) { throw new ArgumentNullException("asyncResult"); } else if(!(asyncResult is AsyncControl)) { throw new ArgumentException(S._("Arg_InvalidAsync")); } else { AsyncControl async = (AsyncControl)asyncResult; async.Wait(this, AsyncOperation.Accept); return async.acceptResult; } } // Begin an asynchronous operation to connect on this socket. public IAsyncResult BeginConnect(EndPoint remoteEP, AsyncCallback callback, Object state) { // Validate the parameters. if(remoteEP == null) { throw new ArgumentNullException("remoteEP"); } else if(remoteEP.AddressFamily != family) { throw new SocketException(Errno.EINVAL); } // Create the result object. AsyncControl async = new AsyncControl (callback, state, this, null, 0, 0, SocketFlags.None, remoteEP, AsyncOperation.Connect); // Start the background process. async.Start(); return async; } // End an asynchronous connect operation. public void EndConnect(IAsyncResult asyncResult) { if(asyncResult == null) { throw new ArgumentNullException("asyncResult"); } else if(!(asyncResult is AsyncControl)) { throw new ArgumentException(S._("Arg_InvalidAsync")); } else { ((AsyncControl)asyncResult).Wait (this, AsyncOperation.Connect); } } // Begin an asynchronous operation to receive on this socket. public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, Object state) { // Validate the parameters. ValidateBuffer(buffer, offset, size); // Create the result object. AsyncControl async = new AsyncControl (callback, state, this, buffer, offset, size, socketFlags, null, AsyncOperation.Receive); // Start the background process. async.Start(); return async; } // End an asynchronous receive operation. public int EndReceive(IAsyncResult asyncResult) { if(asyncResult == null) { throw new ArgumentNullException("asyncResult"); } else if(!(asyncResult is AsyncControl)) { throw new ArgumentException(S._("Arg_InvalidAsync")); } else { AsyncControl async = (AsyncControl)asyncResult; async.Wait(this, AsyncOperation.Receive); return async.result; } } // Begin an asynchronous operation to receive from this socket. public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback callback, Object state) { // Validate the parameters. ValidateBuffer(buffer, offset, size); if(remoteEP == null) { throw new ArgumentNullException("remoteEP"); } else if(remoteEP.AddressFamily != family) { throw new SocketException(Errno.EINVAL); } // Create the result object. AsyncControl async = new AsyncControl (callback, state, this, buffer, offset, size, socketFlags, remoteEP, AsyncOperation.ReceiveFrom); // Start the background process. async.Start(); return async; } // End an asynchronous receive from operation. public int EndReceiveFrom(IAsyncResult asyncResult, ref EndPoint endPoint) { if(asyncResult == null) { throw new ArgumentNullException("asyncResult"); } else if(!(asyncResult is AsyncControl)) { throw new ArgumentException(S._("Arg_InvalidAsync")); } else { AsyncControl async = (AsyncControl)asyncResult; async.Wait(this, AsyncOperation.ReceiveFrom); endPoint = async.remoteEP; return async.result; } } // Begin an asynchronous operation to send on this socket. public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, Object state) { // Validate the parameters. ValidateBuffer(buffer, offset, size); // Create the result object. AsyncControl async = new AsyncControl (callback, state, this, buffer, offset, size, socketFlags, null, AsyncOperation.Send); // Start the background process. async.Start(); return async; } // End an asynchronous send operation. public int EndSend(IAsyncResult asyncResult) { if(asyncResult == null) { throw new ArgumentNullException("asyncResult"); } else if(!(asyncResult is AsyncControl)) { throw new ArgumentException(S._("Arg_InvalidAsync")); } else { AsyncControl async = (AsyncControl)asyncResult; async.Wait(this, AsyncOperation.Send); return async.result; } } // Begin an asynchronous operation to send from this socket. public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP, AsyncCallback callback, Object state) { // Validate the parameters. ValidateBuffer(buffer, offset, size); if(remoteEP == null) { throw new ArgumentNullException("remoteEP"); } else if(remoteEP.AddressFamily != family) { throw new SocketException(Errno.EINVAL); } // Create the result object. AsyncControl async = new AsyncControl (callback, state, this, buffer, offset, size, socketFlags, remoteEP, AsyncOperation.SendTo); // Start the background process. async.Start(); return async; } // End an asynchronous send to operation. public int EndSendTo(IAsyncResult asyncResult) { if(asyncResult == null) { throw new ArgumentNullException("asyncResult"); } else if(!(asyncResult is AsyncControl)) { throw new ArgumentException(S._("Arg_InvalidAsync")); } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -