Write your own Socket framework (1). socket framework
This series only introduces the C # asynchronous Socket framework that can be used in the production environment. If you see similar code elsewhere, don't be surprised. It may be that when I refer to the open source code, directly "plagiarize.
1. Think about the entire socket link processing process in your mind, so you will have it.
2. Start listening. The Code is as follows:
Public override bool Start () {this. _ socket = new System. net. sockets. socket (AddressFamily. interNetwork, SocketType. stream, ProtocolType. tcp); // set KeeyAlive. If the client does not actively send messages, Tcp itself sends a heartbeat packet to notify the server. This is a link for communication. // Avoid waiting for the next communication to know that the link is disconnected. This. _ socket. setSocketOption (SocketOptionLevel. socket, SocketOptionName. keepAlive, true); this. _ socket. setSocketOption (SocketOptionLevel. socket, SocketOptionName. dontLinger, true); try {this. _ socket. bind (base. socketConfig. point); this. _ socket. listen (base. socketConfig. backlog); this. _ socket_args = new SocketAsyncEventArgs (); this. _ socket_args.Completed + = new EventHandler <SocketAsyncEventArgs> (Acc EptSocketCompleted); // when the link is over, if IO is not suspended, AcceptAsync is False, indicating that the synchronization is completed. If (! This. _ socket. acceptAsync (this. _ socket_args) {AcceptSocketCompleted (this. _ socket, this. _ socket_args);} return true;} catch (Exception ex) {return false;} void AcceptSocketCompleted (object sender, SocketAsyncEventArgs e) {System. net. sockets. socket socket = null; if (e. socketError! = SocketError. success) {return;} else {socket = e. acceptSocket;} e. acceptSocket = null; bool willRaiseEvent = false; try {// continue listening to this port. Data Transmission of other links is not affected when processing logic. WillRaiseEvent = this. _ socket. AcceptAsync (e);} catch (Exception ex) {willRaiseEvent = true;} if (socket! = Null) OnNewClientAccepted (socket, null); if (! WillRaiseEvent) AcceptSocketCompleted (null, e );}View Code
3. When the link is over at this time, it is necessary to begin to enter the queue. If there is no such requirement, this step can be ignored. The Code is as follows:
Public class SocketProxy {public System. net. sockets. socket Client; public DateTime Timeout = DateTime. now;} public class SocketConnectionQueue: IDisposable {private Queue <SocketProxy> _ queue; private readonly object _ syncObject = new object (); private bool _ isStop = false; private Thread _ thread; public Action <SocketProxy> Connected; public SocketConnectionQueue () {if (_ queue = null) {_ queue = New Queue <SocketProxy> () ;}if (_ thread = null) {_ thread = new Thread (Thread_Work) {IsBackground = true, Priority = ThreadPriority. highest}; _ thread. start () ;}} public void Push (SocketProxy connect) {lock (_ syncObject) {if (_ queue! = Null) {_ queue. Enqueue (connect) ;}} public void Thread_Work () {while (! _ IsStop) {SocketProxy [] socketConnect = null; lock (_ syncObject) {if (_ queue. count> 0) {socketConnect = new SocketProxy [_ queue. count]; _ queue. copyTo (socketConnect, 0); _ queue. clear () ;}} if (socketConnect! = Null & socketConnect. Length> 0) {foreach (var client in socketConnect) {if (Connected! = Null) {Connected. Invoke (client) ;}} Thread. Sleep (10) ;}} public void Dispose () {_ isStop = true; if (_ thread! = Null) {_ thread. Join ();}}}View Code
4. After Entering the queue, you must allocate resources from the link pool. You can also instantiate a link when each request comes, and then add the link to the pool, my approach is to allocate resources when the program is initialized. The Code is as follows:
Public class SocketConnectionPool: IDisposable {private ServerConfig _ serverConfig; public IAppServer AppServer; private ConcurrentStack <SocketConnection> _ connectPool; private long connect_id = 0; private byte [] _ buffer; private readonly object _ syncObject = new object (); private SocketConnectionQueue _ queue; public Action <System. net. sockets. socket, SocketConnection> Connected; public long Gener AteId () {if (connect_id = long. maxValue) {connect_id = 0;} connect_id ++; return connect_id;} public SocketConnectionPool (IAppServer server) {this. appServer = server; this. _ serverConfig = server. appConfig;} public void Init () {var connects = new List <SocketConnection> (this. _ serverConfig. maxConnectionNumber); _ buffer = new byte [this. _ serverConfig. bufferSize]; SocketAsyncEventArgs arg; for (v Ar I = 0; I <this. _ serverConfig. maxConnectionNumber; I ++) {arg = new SocketAsyncEventArgs (); arg. setBuffer (_ buffer, 0, _ buffer. length); connects. add (new SocketConnection (arg, this);} _ connectPool = new ConcurrentStack <SocketConnection> (connects); if (_ queue = null) {_ queue = new SocketConnectionQueue ();} _ queue. connected = OnConnected;} public void Push (System. net. sockets. socket socket ){ SocketProxy proxy = new SocketProxy () {Client = socket}; _ queue. push (proxy);} public void OnConnected (SocketProxy proxy) {// if the link in the queue is not allocated to resources within the Timeout time, the link is closed and discarded. Int timeout = (int) (DateTime. now-proxy. timeout ). totalSeconds; if (timeout> = this. _ serverConfig. timeout) {proxy. client. close (); return;} else {// not allocated to the resource re-entry column. SocketConnection connect = this. GetConnectionFromPool (); if (connect = null) {_ queue. Push (proxy);} else {if (this. Connected! = Null) {this. connected (proxy. client, connect) ;}}}/// <summary> /// retrieve the link from the link pool (LIFO) /// </summary> /// <returns> </returns> public SocketConnection GetConnectionFromPool () {// _ queue. push (); SocketConnection connect; if (! _ ConnectPool. tryPop (out connect) {return null;} lock (_ syncObject) {long connect_id = this. generateId (); connect. connectId = connect_id;} return connect;} // <summary> // release the link, and put back the connection pool // </summary> // <param name = "connect"> </param> public void ReleaseConnection (SocketConnection connect) {_ connectPool. push (connect); LogHelper. debug (connect. connectId + "pool");} public void Dispose () {_ queue. dispose ();}}View Code
Many socketconnections are initialized in Init (). This is the class we use to manage a specific single link. The Code is as follows:
Public class SocketConnection {public SocketFlag Flag {get; private set;} public SocketConnectionPool Pool {get {return _ pool;} private set {}} private SocketConnectionPool _ pool; public SocketAsyncEventArgs RecevieEventArgs {get; set;} public long ConnectId {get; set;} public SocketConnection () {this. flag = SocketFlag. error;} public SocketConnection (SocketAsyncEventArgs args, SocketConnectionPool pool) {RecevieEventArgs = args; RecevieEventArgs. completed + = new EventHandler <SocketAsyncEventArgs> (SocketEventArgs_Completed); this. flag = SocketFlag. busy; this. _ pool = pool;} void SocketEventArgs_Completed (object sender, SocketAsyncEventArgs e) {var socketSession = e. userToken as SocketSession; if (socketSession = null) {this. flag = SocketFlag. error; this. close (); return;} switch (e. lastOperation) {case SocketAsyncOperation. receive: socketSession. receiveData (e); break; default: break;} public void Initialise (SocketSession session) {this. recevieEventArgs. userToken = session; this. flag = SocketFlag. busy; session. closed + = () => {this. close () ;};} public void Reset () {// ConnectId = 0; this. recevieEventArgs. userToken = null; this. flag = SocketFlag. idle;} private void Close () {this. reset (); LogHelper. debug (ConnectId + "reset"); this. _ pool. releaseConnection (this );}}View Code
Use socket to write a connection-oriented network programming framework for me
This ..... Source code?
Socket Problems
First, the second CLOSE call is called only after the communication is complete. The first one is closed when an error occurs.
Second, fork returns the BOOL value.
Programs Written by SOCKET can be used across operating systems. WINSOCK is a network programming interface implemented by WINDOWS. The program can only be used on WINDOWS.
The SOCKET in C # has restrictions on the. net Framework Structure, which makes programming easier. You can solve the problem of multithreading.
In addition, it is very difficult to use VC ++ to write network programming at the initial stage. We recommend that you have 2 years of VC development experience before doing underlying network programming.
If you sent me a Baidu message from Sichuan Province, I have some experience in C # And VC program development and what I did. I can give it to you.