From 7b657424367b2ac990c21253d84c08d3972ac99a Mon Sep 17 00:00:00 2001 From: SpringHgui <740360381@qq.com> Date: Mon, 13 Jul 2020 10:51:03 +0800 Subject: [PATCH] add dockerfile --- .dockerignore | 25 ++ FastTunnel.Core/Core/SuiDaoServer.cs | 2 +- FastTunnel.Core/Server.cs | 252 ++++++++++++++++++ FastTunnel.Server/Dockerfile | 21 ++ FastTunnel.Server/FastTunnel.Server.csproj | 2 + .../Properties/launchSettings.json | 10 + 6 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 FastTunnel.Core/Server.cs create mode 100644 FastTunnel.Server/Dockerfile create mode 100644 FastTunnel.Server/Properties/launchSettings.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3729ff0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/FastTunnel.Core/Core/SuiDaoServer.cs b/FastTunnel.Core/Core/SuiDaoServer.cs index 0cfbcf5..3730e43 100644 --- a/FastTunnel.Core/Core/SuiDaoServer.cs +++ b/FastTunnel.Core/Core/SuiDaoServer.cs @@ -258,7 +258,7 @@ namespace FastTunnel.Core.Core private IServerHandler HandleWords(string words, Socket client) { // 同时读到两个或多个指令 - var index = words.IndexOf("}{"); + var index = words.IndexOf("\n"); if (index > 0) { _logger.LogError($"读到多个消息 {words}"); diff --git a/FastTunnel.Core/Server.cs b/FastTunnel.Core/Server.cs new file mode 100644 index 0000000..ffd4e33 --- /dev/null +++ b/FastTunnel.Core/Server.cs @@ -0,0 +1,252 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; + +namespace FastTunnel.Core +{ + // Implements the connection logic for the socket server. + // After accepting a connection, all data read from the client + // is sent back to the client. The read and echo back to the client pattern + // is continued until the client disconnects. + class Server + { + private int m_numConnections; // the maximum number of connections the sample is designed to handle simultaneously + private int m_receiveBufferSize;// buffer size to use for each socket I/O operation + BufferManager m_bufferManager; // represents a large reusable set of buffers for all socket operations + const int opsToPreAlloc = 2; // read, write (don't alloc buffer space for accepts) + Socket listenSocket; // the socket used to listen for incoming connection requests + // pool of reusable SocketAsyncEventArgs objects for write, read and accept socket operations + SocketAsyncEventArgsPool m_readWritePool; + int m_totalBytesRead; // counter of the total # bytes received by the server + int m_numConnectedSockets; // the total number of clients connected to the server + Semaphore m_maxNumberAcceptedClients; + + // Create an uninitialized server instance. + // To start the server listening for connection requests + // call the Init method followed by Start method + // + // the maximum number of connections the sample is designed to handle simultaneously + // buffer size to use for each socket I/O operation + public Server(int numConnections, int receiveBufferSize) + { + m_totalBytesRead = 0; + m_numConnectedSockets = 0; + m_numConnections = numConnections; + m_receiveBufferSize = receiveBufferSize; + // allocate buffers such that the maximum number of sockets can have one outstanding read and + //write posted to the socket simultaneously + m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc, + receiveBufferSize); + + m_readWritePool = new SocketAsyncEventArgsPool(numConnections); + m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); + } + + // Initializes the server by preallocating reusable buffers and + // context objects. These objects do not need to be preallocated + // or reused, but it is done this way to illustrate how the API can + // easily be used to create reusable objects to increase server performance. + // + public void Init() + { + // Allocates one large byte buffer which all I/O operations use a piece of. This gaurds + // against memory fragmentation + m_bufferManager.InitBuffer(); + + // preallocate pool of SocketAsyncEventArgs objects + SocketAsyncEventArgs readWriteEventArg; + + for (int i = 0; i < m_numConnections; i++) + { + //Pre-allocate a set of reusable SocketAsyncEventArgs + readWriteEventArg = new SocketAsyncEventArgs(); + readWriteEventArg.Completed += new EventHandler(IO_Completed); + readWriteEventArg.UserToken = new AsyncUserToken(); + + // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object + m_bufferManager.SetBuffer(readWriteEventArg); + + // add SocketAsyncEventArg to the pool + m_readWritePool.Push(readWriteEventArg); + } + } + + // Starts the server such that it is listening for + // incoming connection requests. + // + // The endpoint which the server will listening + // for connection requests on + public void Start(IPEndPoint localEndPoint) + { + // create the socket which listens for incoming connections + listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + listenSocket.Bind(localEndPoint); + // start the server with a listen backlog of 100 connections + listenSocket.Listen(100); + + // post accepts on the listening socket + StartAccept(null); + + //Console.WriteLine("{0} connected sockets with one outstanding receive posted to each....press any key", m_outstandingReadCount); + Console.WriteLine("Press any key to terminate the server process...."); + Console.ReadKey(); + } + + // Begins an operation to accept a connection request from the client + // + // The context object to use when issuing + // the accept operation on the server's listening socket + public void StartAccept(SocketAsyncEventArgs acceptEventArg) + { + if (acceptEventArg == null) + { + acceptEventArg = new SocketAsyncEventArgs(); + acceptEventArg.Completed += new EventHandler(AcceptEventArg_Completed); + } + else + { + // socket must be cleared since the context object is being reused + acceptEventArg.AcceptSocket = null; + } + + m_maxNumberAcceptedClients.WaitOne(); + bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg); + if (!willRaiseEvent) + { + ProcessAccept(acceptEventArg); + } + } + + // This method is the callback method associated with Socket.AcceptAsync + // operations and is invoked when an accept operation is complete + // + void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) + { + ProcessAccept(e); + } + + private void ProcessAccept(SocketAsyncEventArgs e) + { + Interlocked.Increment(ref m_numConnectedSockets); + Console.WriteLine("Client connection accepted. There are {0} clients connected to the server", + m_numConnectedSockets); + + // Get the socket for the accepted client connection and put it into the + //ReadEventArg object user token + SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop(); + ((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket; + + // As soon as the client is connected, post a receive to the connection + bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs); + if (!willRaiseEvent) + { + ProcessReceive(readEventArgs); + } + + // Accept the next connection request + StartAccept(e); + } + + // This method is called whenever a receive or send operation is completed on a socket + // + // SocketAsyncEventArg associated with the completed receive operation + void IO_Completed(object sender, SocketAsyncEventArgs e) + { + // determine which type of operation just completed and call the associated handler + switch (e.LastOperation) + { + case SocketAsyncOperation.Receive: + ProcessReceive(e); + break; + case SocketAsyncOperation.Send: + ProcessSend(e); + break; + default: + throw new ArgumentException("The last operation completed on the socket was not a receive or send"); + } + } + + // This method is invoked when an asynchronous receive operation completes. + // If the remote host closed the connection, then the socket is closed. + // If data was received then the data is echoed back to the client. + // + private void ProcessReceive(SocketAsyncEventArgs e) + { + // check if the remote host closed the connection + AsyncUserToken token = (AsyncUserToken)e.UserToken; + if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) + { + //increment the count of the total bytes receive by the server + Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred); + Console.WriteLine("The server has read a total of {0} bytes", m_totalBytesRead); + + //echo the data received back to the client + e.SetBuffer(e.Offset, e.BytesTransferred); + bool willRaiseEvent = token.Socket.SendAsync(e); + if (!willRaiseEvent) + { + ProcessSend(e); + } + } + else + { + CloseClientSocket(e); + } + } + + // This method is invoked when an asynchronous send operation completes. + // The method issues another receive on the socket to read any additional + // data sent from the client + // + // + private void ProcessSend(SocketAsyncEventArgs e) + { + if (e.SocketError == SocketError.Success) + { + // done echoing data back to the client + AsyncUserToken token = (AsyncUserToken)e.UserToken; + // read the next block of data send from the client + bool willRaiseEvent = token.Socket.ReceiveAsync(e); + if (!willRaiseEvent) + { + ProcessReceive(e); + } + } + else + { + CloseClientSocket(e); + } + } + + private void CloseClientSocket(SocketAsyncEventArgs e) + { + AsyncUserToken token = e.UserToken as AsyncUserToken; + + // close the socket associated with the client + try + { + token.Socket.Shutdown(SocketShutdown.Send); + } + // throws if client process has already closed + catch (Exception) { } + token.Socket.Close(); + + // decrement the counter keeping track of the total number of clients connected to the server + Interlocked.Decrement(ref m_numConnectedSockets); + + // Free the SocketAsyncEventArg so they can be reused by another client + m_readWritePool.Push(e); + + m_maxNumberAcceptedClients.Release(); + Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets); + } + } + + internal class AsyncUserToken + { + public System.Net.Sockets.Socket Socket { get; set; } + } +} diff --git a/FastTunnel.Server/Dockerfile b/FastTunnel.Server/Dockerfile new file mode 100644 index 0000000..507f549 --- /dev/null +++ b/FastTunnel.Server/Dockerfile @@ -0,0 +1,21 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build +WORKDIR /src +COPY ["FastTunnel.Server/FastTunnel.Server.csproj", "FastTunnel.Server/"] +COPY ["FastTunnel.Core/FastTunnel.Core.csproj", "FastTunnel.Core/"] +RUN dotnet restore "FastTunnel.Server/FastTunnel.Server.csproj" +COPY . . +WORKDIR "/src/FastTunnel.Server" +RUN dotnet build "FastTunnel.Server.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "FastTunnel.Server.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "FastTunnel.Server.dll"] \ No newline at end of file diff --git a/FastTunnel.Server/FastTunnel.Server.csproj b/FastTunnel.Server/FastTunnel.Server.csproj index 5882760..bc299d0 100644 --- a/FastTunnel.Server/FastTunnel.Server.csproj +++ b/FastTunnel.Server/FastTunnel.Server.csproj @@ -2,6 +2,7 @@ Exe netcoreapp3.1 + Linux @@ -15,6 +16,7 @@ + diff --git a/FastTunnel.Server/Properties/launchSettings.json b/FastTunnel.Server/Properties/launchSettings.json new file mode 100644 index 0000000..7a6b163 --- /dev/null +++ b/FastTunnel.Server/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "FastTunnel.Server": { + "commandName": "Project" + }, + "Docker": { + "commandName": "Docker" + } + } +} \ No newline at end of file