Asynchronous C# server[转]
It hasn't been thoroughly tested, but seems to work OK.
This should scale pretty nicely as well. Originally I was going to code it in C++, but after doing some research the scalability factor that I thought was going to gain using C++ seemed to be low considering the amount of work it was going to take.
Server.cs
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net; namespace Server
{ public class Server
{
private int port;
private Socket serversocket; public delegate void ConnectionEvent(Connection conn);
public List<Connection> connections;
public event ConnectionEvent AcceptCallback;
public event ConnectionEvent RecieveCallback;
public event ConnectionEvent DisconnectCallback; public Server(int p)
{
port = p;
connections = new List<Connection>();
} public bool Start()
{
IPEndPoint ipendpoint; try
{ //do not assign an IP, as it is a server (IPAdress.Any)
ipendpoint = new IPEndPoint(IPAddress.Any, this.port); }
catch (ArgumentOutOfRangeException e)
{
//port was probably out of range
throw new ArgumentOutOfRangeException("Please check port number.", e); } try
{ //create the main server worker socket
serversocket = new Socket(ipendpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); }
catch (SocketException e)
{ //here because we couldn't create server socket
throw new ApplicationException("Couldn't create server socket.", e); } try
{
//bind the socket to the specified port
serversocket.Bind(ipendpoint); //begin listening for incoming connections
serversocket.Listen(); }
catch (SocketException e)
{ //probably here due to the port being in use
throw new ApplicationException("Couldn't bind/listen on port: " + this.port.ToString(), e); } try
{ //begin accepting incoming connections
serversocket.BeginAccept(new AsyncCallback(acceptCallback), this.serversocket); }
catch (Exception e)
{ throw new ApplicationException("Error assigning the accept callback.", e); } return true;
} private void acceptCallback(IAsyncResult ar)
{
Connection conn = new Connection(); try
{ //finish the connection //get the resulting state object
Socket sck = (Socket)ar.AsyncState; //create new connection object to be added to our concurrent connection list
conn = new Connection(sck.EndAccept(ar)); //lock our list for thread safety
lock(connections)
{ //add to our list
connections.Add(conn); } //begin accepting data on that socket, using our Connection object as the object state
conn.socket.BeginReceive(conn.buffer, , conn.buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), conn); //start accepting connections again
serversocket.BeginAccept(new AsyncCallback(acceptCallback), this.serversocket); //if the eventhandler for incoming connections has been assgined, call it
if(AcceptCallback != null)
{ AcceptCallback(conn); } }
catch(SocketException e)
{
Disconnect(conn);
throw new ApplicationException(e.Message, e);
}
} private void Disconnect(Connection conn)
{
//remove connection from list
lock (connections)
{
connections.Remove(conn);
} //make sure it's completely closed
conn.socket.Close(); //if the eventhandler for disconnection has been assgined, call it
if (DisconnectCallback != null)
{ DisconnectCallback(conn); }
} private void receiveCallback(IAsyncResult ar)
{ //retrieve the connection that has data ready
Connection conn = (Connection)ar.AsyncState; try
{ //retrieve the data(bytes) while also returning how many bytes were read
int bytes = conn.socket.EndReceive(ar); //if bytes is more than zero, then data was successfully read
if(bytes > )
{ //if the data receive callback has been assigned, call it
if(RecieveCallback != null)
{ RecieveCallback(conn); } //being receiving data again
conn.socket.BeginReceive(conn.buffer, , conn.buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), conn); }
else
{ //if zero bytes were read, connection was closed
Disconnect(conn); }
}
catch(SocketException e)
{ Disconnect(conn);
throw new ApplicationException("Error with EndReceive or BeginReceive", e);
}
}
}
}
Connection.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets; namespace Server
{ public class Connection
{
public byte[] buffer;
public Socket socket; public Connection()
{ }
public Connection(Socket sock)
{
buffer = new byte[];
socket = sock;
} public void Send(string data)
{
try
{ if (this.socket.Connected)
{
//convert string into an aray of bytes
byte[] buffer = ASCIIEncoding.ASCII.GetBytes(data); //send our byte[] buffer
socket.Send(buffer, SocketFlags.None);
} }
catch (SocketException e)
{
throw new ApplicationException("Error with Send", e);
}
} }
}
Usage:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading; namespace Server
{
class Program
{
static void Main(string[] args)
{
//port 80(webserver)
Server server = new Server( ); server.RecieveCallback += server_RecieveCallback;
server.AcceptCallback += server_AcceptCallback;
server.DisconnectCallback += server_DisconnectCallback;
server.Start(); ThreadStart threadstart = new ThreadStart(ThreadJob);
Thread thread = new Thread(threadstart); thread.Start(); } static void server_DisconnectCallback(Connection conn)
{
Console.WriteLine("Connection disconnected\n");
} static void server_AcceptCallback(Connection conn)
{
Console.WriteLine("Incoming connection\n");
} static void ThreadJob()
{
while (true)
Thread.Sleep();
} static void server_RecieveCallback(Connection conn)
{ Console.WriteLine(ASCIIEncoding.ASCII.GetString(conn.buffer)); }
}
}
Go to your web browser and type 127.0.0.1 into the address bar.
If any one sees any issues and things to improve on, let me know. (Sure there is).
If any one has any questions let me know.
Asynchronous C# server[转]的更多相关文章
- SQL Server数据库连接字符串的组成
DB驱动程序常见的驱动程序如下: ODBC ODBC(Open Database Connectivity,开放数据库互连)是微软公司开放服务结构(WOSA,Windows Open Servic ...
- 可扩展多线程异步Socket服务器框架EMTASS 2.0 续
转载自Csdn:http://blog.csdn.net/hulihui/article/details/3158613 (原创文章,转载请注明来源:http://blog.csdn.net/huli ...
- Netty学习笔记
一些类与方法说明 1)ByteBuf ByteBuf的API说明: Creation of a buffer It is recommended to create a new buffer usin ...
- Best packages for data manipulation in R
dplyr and data.table are amazing packages that make data manipulation in R fun. Both packages have t ...
- Node.js 进程平滑离场剖析
本文由云+社区发表 作者:草小灰 使用 Node.js 搭建 HTTP Server 已是司空见惯的事.在生产环境中,Node 进程平滑重启直接关系到服务的可靠性,它的重要性不容我们忽视.既然是平滑重 ...
- 针对UDP丢包问题,进行系统层面和程序层面调优
转自:https://blog.csdn.net/xingzheouc/article/details/49946191 1. UDP概念 用户数据报协议(英语:User Datagram Proto ...
- C# WinForm开发系列 - 文章索引
该系列主要整理收集在使用C#开发WinForm应用文章及相关代码, 平时看到大家主要使用C#来开发Asp.Net应用,这方面的文章也特别多,而关于WinForm的文章相对少很多,而自己对WinForm ...
- 异步Socket服务器与客户端
本文灵感来自Andre Azevedo 在CodeProject上面的一片文章,An Asynchronous Socket Server and Client,讲的是异步的Socket通信. S ...
- 学习笔记之JSON
JSON https://www.json.org/ JSON (JavaScript Object Notation) is a lightweight data-interchange forma ...
随机推荐
- [Linux] 009 链接命令
链接命令:ln 命令名称:ln 命令英文原意:link 命令所在路径:/bin/ln 执行权限:所有用户 语法:ln -s [原文件] [目标文件] 功能描述:生成链接文件 范例: 创建文件 /etc ...
- spring-第五篇之spring容器中的bean
1.bean的基本定义和bean别名 2.容器中bean的作用域 singleton:单例模式,在整个spring IoC容器中,singleton作用域的bean将只生成一个实例. prototyp ...
- jsoncpp解析非json串
转自:https://www.cnblogs.com/huojing/articles/5927488.html 由于Jsoncpp解析非法json时,会自动容错成字符类型.对字符类型取下标时,会触发 ...
- python——datetime模块
一.datetime模块介绍 (一).datetime模块中包含如下类: 类名 功能说明 date 日期对象,常用的属性有year, month, day time 时间对象 datetime 日期时 ...
- BZOJ 1683.City skyline 城市地平线
传送门 从左到右扫一遍,考虑什么时候会和之前形成同一幢房子从而不用统计 显然是当前的高度和之前某个点高度相同,并且它们之间没有更矮的建筑 考虑用一个单调栈维护一个单调上升的房子轮廓,然后对于扫到的每一 ...
- AI-Tensorflow-神经网络优化算法-梯度下降算法-学习率
记录内容来自<Tensorflow实战Google一书>及MOOC人工智能实践 http://www.icourse163.org/learn/PKU-1002536002?tid=100 ...
- 2019-9-2-win10-UWP-MvvmLight入门
title author date CreateTime categories win10 UWP MvvmLight入门 lindexi 2019-09-02 12:57:38 +0800 2018 ...
- numpy知识点总结
一.数组方法 创建数组:arange()创建一维数组:array()创建一维或多维数组,其参数是类似于数组的对象,如列表等 反过来转换则可以使用numpy.ndarray.tolist()函数,如a. ...
- weblogic启动脚本01
DATE=`date +%Y%m%d%H%M%S` user=`whoami` logDir=/app/logs/sguap_admin #启动日志存放路径sguap是例子系统简称# logDestd ...
- 树的计数 Prüfer编码与Cayley公式 学习笔记
最近学习了Prüfer编码与Cayley公式,这两个强力的工具一般用于解决树的计数问题.现在博主只能学到浅层的内容,只会用不会证明. 推荐博客:https://blog.csdn.net/moreja ...