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 ...
随机推荐
- PA动画使用教程
1.动画复制与动画粘贴.动画删除 PA的动画复制.动画粘贴不会覆盖原有动画: PPT自带的动画刷会覆盖原有动画: 注意: 超级属性的动画复制.粘贴有bug,应使用自带的动画刷: PA动画的复制.粘贴只 ...
- 【python】含中文字符串截断
对于含多字节的字符串,进行截断的时候,要判断截断处是几字节字符,不能将多字节从中分割,避免截断后乱码 下面给出utf8和gb18030上的实现, 用任何一种都可以,可以先进行转码,用encode, d ...
- 使用母版页的Web窗体不走Page_Load
原因:母版页--->属性--->生成--->输出路径,这里我将它的默认/bin路径更改了,所以才导致使用此母版页的其它页面也不走Page_Load方法 解决:改回默认的输出路径
- ECharts 知识笔记
涓滴之水终可磨损大石,不是由于它的力量强大,而是由于昼夜不舍的滴坠 定制label样式(图标上显示的对应文字 对文字一些样式的修改) (1)通过“formatter”实现内容自定义: (2)通过“ri ...
- Invalid column name on sql server update after column create
问题:新建一个测试表xx as code into xx select * from xx 给这个表添加一个列val, val列不允许为空,将表中已有的数据val值更新为1 alter table x ...
- 玩爆你的手机联系人--T9搜索(一)
自己研究了好几天联系人的T9搜索算法, 先分享出来给大家看看. 欢迎不吝赐教.假设有大神有更好的T9搜索算法, 那更好啊,大家一起研究研究,谢谢. 第一部分是比較简单的获取手机联系人. 获取 ...
- vsftpd.service: Main process exited, code=exited, status=2/INVALIDARGUMENT和vsftpd:500 OOPS: vsftpd: refusing to run with writable root inside chroot ()错误的解决方法
今天在配置VSFTPD过程中遇到两个错误 1是启动失败,通过 SERVICE VSFTPD STATUS 查看到报错 May 02 16:06:58 debian systemd[1]: Starti ...
- BJSV-P-002高精度测速一体机
测速.抓拍.录像于一体,产品处于行业顶尖水平. 1 测速一体机参数 2 接口和资源 3 相机接口 1. 前面板接口 测速一体机镜头接口采用C-Mount ...
- Linux学习笔记之档案权限与目录配置
一. 档案权限与目录配置用户的属性信息: /etc/passwd用户的密码信息: /etc/shadow组的信息: /etc/group 每个用户都有唯一的UID供系统识别sudo -i 输入 ...
- 一、Iframe
一.Iframe 自适应iframe的高 <!-- frameborder :设置iframe的边框 scrolling:设置iframe的滚动条 src:设置iframe的路径 onload: ...