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