using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Text;
namespace Rocky.Net
{
/// <summary>
/// The socket does socket communication in the Synchronous way.It is better used as a server socket.
/// </summary>
public static class SynchronousSocket
{
#region StaticMembers
private const int CONNECTED_WAITTIME = 50;
private static SyncDictionary listeners;
static SynchronousSocket()
{
listeners = new SyncDictionary();
}
#region Listen
public static void StartListen(IPEndPoint localEndPoint, Action<Socket> accepted)
{
if (listeners.Contains(localEndPoint))
{
throw new ArgumentException();
}
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(100);
listeners.Add(localEndPoint, listener);
Thread thread = new Thread(_localEndPoint =>
{
while (listeners.Contains(_localEndPoint))
{
Socket _listener = (Socket)listeners[_localEndPoint];
Socket connectedSocket = _listener.Accept();
// Wait for the connection to be stabilized.
Thread.Sleep(CONNECTED_WAITTIME);
// Call the SocketConnected event.
if (accepted != null)
{
accepted(connectedSocket);
}
}
});
thread.IsBackground = true;
thread.Start(localEndPoint);
}
public static void StopListen(IPEndPoint localEndPoint)
{
if (!listeners.Contains(localEndPoint))
{
throw new ArgumentException();
}
Socket listener = (Socket)listeners[localEndPoint];
listener.Shutdown(SocketShutdown.Both);
listener.Close();
listeners.Remove(localEndPoint);
}
#endregion
#region Send&Receive
public static void Send(Socket connectedSocket, byte[] buffer, Action<int, int> preSent)
{
Send(connectedSocket, buffer, 0, buffer.Length, preSent);
}
public static void Send(Socket connectedSocket, byte[] buffer, int offset, int size, Action<int, int> preSent)
{
byte[] first = new byte[4];
BufferStream.Write(size, first, 0);
connectedSocket.Send(first);
int sent = offset;
while (sent < size)
{
sent += connectedSocket.Send(buffer, sent, size - sent, SocketFlags.None);
if (preSent != null)
{
preSent(sent, size);
}
}
}
public static void Receive(Socket connectedSocket, byte;">[] buffer, Action<int, int> preRecv)
{
int size;
Receive(connectedSocket, buffer, 0, out size, preRecv);
}
public static void Receive(Socket connectedSocket, byte[] buffer, int offset, out int size, Action<int, int> preRecv)
{
byte[] first = new byte[4];
connectedSocket.Receive(first);
BufferStream.Read(out size, first, 0);
if (buffer.Length < size)
{
buffer = new byte[size];
}
int recv = offset;
while (recv < size)
{
recv += connectedSocket.Receive(buffer, recv, size - recv, SocketFlags.None);
if (preRecv != null)
{
preRecv(recv, size);
}
}
}
#endregion
public static void TransmitFile(Socket connectedSocket, string filePath)
{
byte[] buffer = new byte[BufferStream.MaxBufferSize];
using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, BufferStream.MaxBufferSize))
{
BufferStream.Write(stream.Length, buffer, 0);
char[] fileName = Path.GetFileName(filePath).ToCharArray();
int size = Encoding.Default.GetBytes(fileName, 0, fileName.Length, buffer, 8) + 8;
connectedSocket.Send(buffer, 0, size, SocketFlags.None);
int sent;
while ((size = stream.Read(buffer, 0, BufferStream.MaxBufferSize)) != 0)
{
sent = 0;
while (sent < size)
{
sent += connectedSocket.Send(buffer, sent, size - sent, SocketFlags.None);
}
}
}
}
/// <summary>
/// Accept a file through the socket communication.
/// </summary>
/// <param name="connectedSocket">A connected socket.</param>
/// <param name="fileName">Save file name.</param>
public static void AcceptFile(Socket connectedSocket, string path)
{
byte[] buffer = new byte[BufferStream.MaxBufferSize];
int size = connectedSocket.Receive(buffer);
long fileSize;
BufferStream.Read(out fileSize, buffer, 0);
string filePath = Path.GetDirectoryName(path) + Encoding.Default.GetString(buffer, 8, size - 8);
using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, BufferStream.MaxBufferSize))
{
long receivedBytes = 0L;
int recv;
while (receivedBytes < fileSize)
{
stream.Write(buffer, 0, recv = connectedSocket.Receive(buffer));
stream.Flush();
receivedBytes += recv;
}
}
}
#endregion
}
}