mirror of
https://github.com/FastTunnel/FastTunnel.git
synced 2025-02-07 18:19:34 +08:00
add dockerfile
This commit is contained in:
parent
2904430b71
commit
7b65742436
25
.dockerignore
Normal file
25
.dockerignore
Normal file
|
@ -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
|
|
@ -258,7 +258,7 @@ namespace FastTunnel.Core.Core
|
||||||
private IServerHandler HandleWords(string words, Socket client)
|
private IServerHandler HandleWords(string words, Socket client)
|
||||||
{
|
{
|
||||||
// 同时读到两个或多个指令
|
// 同时读到两个或多个指令
|
||||||
var index = words.IndexOf("}{");
|
var index = words.IndexOf("\n");
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
{
|
{
|
||||||
_logger.LogError($"读到多个消息 {words}");
|
_logger.LogError($"读到多个消息 {words}");
|
||||||
|
|
252
FastTunnel.Core/Server.cs
Normal file
252
FastTunnel.Core/Server.cs
Normal file
|
@ -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
|
||||||
|
//
|
||||||
|
// <param name="numConnections">the maximum number of connections the sample is designed to handle simultaneously</param>
|
||||||
|
// <param name="receiveBufferSize">buffer size to use for each socket I/O operation</param>
|
||||||
|
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<SocketAsyncEventArgs>(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.
|
||||||
|
//
|
||||||
|
// <param name="localEndPoint">The endpoint which the server will listening
|
||||||
|
// for connection requests on</param>
|
||||||
|
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
|
||||||
|
//
|
||||||
|
// <param name="acceptEventArg">The context object to use when issuing
|
||||||
|
// the accept operation on the server's listening socket</param>
|
||||||
|
public void StartAccept(SocketAsyncEventArgs acceptEventArg)
|
||||||
|
{
|
||||||
|
if (acceptEventArg == null)
|
||||||
|
{
|
||||||
|
acceptEventArg = new SocketAsyncEventArgs();
|
||||||
|
acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(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
|
||||||
|
//
|
||||||
|
// <param name="e">SocketAsyncEventArg associated with the completed receive operation</param>
|
||||||
|
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
|
||||||
|
//
|
||||||
|
// <param name="e"></param>
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
21
FastTunnel.Server/Dockerfile
Normal file
21
FastTunnel.Server/Dockerfile
Normal file
|
@ -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"]
|
|
@ -2,6 +2,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="Program.cs.BASE.cs" />
|
<Compile Remove="Program.cs.BASE.cs" />
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.1.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.1.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.9" />
|
||||||
<PackageReference Include="NLog" Version="4.6.8" />
|
<PackageReference Include="NLog" Version="4.6.8" />
|
||||||
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.1" />
|
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
10
FastTunnel.Server/Properties/launchSettings.json
Normal file
10
FastTunnel.Server/Properties/launchSettings.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"FastTunnel.Server": {
|
||||||
|
"commandName": "Project"
|
||||||
|
},
|
||||||
|
"Docker": {
|
||||||
|
"commandName": "Docker"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user