c#Socket服务器与客户端的开发(1)
上个项目中用到了Socket通讯,项目中直接借助SuperSocket实现,但是我觉得这毕竟是一个我没接触过的东西,所以也顺便学习了一下原生socket的使用,做了一个socket服务器与客户端的开发.本人菜鸟一枚,只做了一个简单的实现,希望有看到我博客的大佬不吝指点,抱拳!
socket通讯的相关知识的话,在博客园中的大佬们总结的贴子已经非常多,也很详细,忘记了就在去看。
这里总结一下原生的Socket和SuperSocket的使用(官方定义:SuperSocket 是一个轻量级, 跨平台而且可扩展的 .Net/Mono Socket 服务器程序框架。你无须了解如何使用 Socket, 如何维护 Socket 连接和 Socket 如何工作,但是你却可以使用 SuperSocket 很容易的开发出一款 Socket 服务器端软件,例如游戏服务器,GPS 服务器, 工业控制服务和数据采集服务器等等。)
下边是一个Socket测试工具 十分好用!
链接:https://pan.baidu.com/s/1ykEofUIZKE2yhe3mMyRbJw
提取码:m2nk
先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
原生Socket实现SocketServer:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading; namespace DotnetSockets
{
public partial class DotnetSocketServer : Form
{
public DotnetSocketServer()
{
InitializeComponent();
} //存储已连接的客户端的泛型集合
private static Dictionary<string, Socket> socketList = new Dictionary<string, Socket>(); /// <summary>
/// 接收连接
/// </summary>
/// <param name="obj"></param>
public void StartServer(object obj)
{
string str;
while (true)
{
//等待接收客户端连接 Accept方法返回一个用于和该客户端通信的Socket
Socket recviceSocket = ((Socket)obj).Accept();
//获取客户端ip和端口号
str = recviceSocket.RemoteEndPoint.ToString();
socketList.Add(str, recviceSocket);
//控件调用invoke方法 解决"从不是创建控件的线程访问它"的异常
cmb_socketlist.Invoke(new Action(() => { cmb_socketlist.Items.Add(str); }));
richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText(str + "已连接" + "\r\n"); })); //Accept()执行过后 当前线程会阻塞 只有在有客户端连接时才会继续执行
//创建新线程,监控接收新客户端的请求数据
Thread thread = new Thread(startRecive);
thread.IsBackground = true;
thread.Start(recviceSocket);
}
} /// <summary>
/// 接收消息
/// </summary>
/// <param name="obj">客户端socket</param>
public void startRecive(object obj)
{
string str;
string ip;
while (true)
{ byte[] buffer = new byte[];
int count;
try
{
//Receive(Byte[]) 从绑定的 Socket 套接字接收数据,将数据存入接收缓冲区。
//该方法执行过后同Accept()方法一样 当前线程会阻塞 等到客户端下一次发来数据时继续执行
count = ((Socket)obj).Receive(buffer);
ip = ((Socket)obj).RemoteEndPoint.ToString();
if (count == )
{
cmb_socketlist.Invoke(new Action(() => { cmb_socketlist.Items.Remove(ip); }));
richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText(ip + "已断开连接" + "\r\n"); }));
break;
}
else
{
str = Encoding.Default.GetString(buffer, , count);
richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText("收到"+ip+"数据 " + str + "\r\n"); })); }
}
catch (Exception)
{ }
}
} /// <summary>
/// 开启服务器监听
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_StartListen_Click(object sender, EventArgs e)
{
//实例化一个Socket对象,确定网络类型、Socket类型、协议类型
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint IEP = new IPEndPoint(IPAddress.Parse(txt_ip.Text), int.Parse(txt_port.Text));
//绑定ip和端口
socket.Bind(IEP);
//开启监听
socket.Listen(); richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText("开始监听" + "\r\n"); })); Thread thread = new Thread(new ParameterizedThreadStart(StartServer));
thread.IsBackground = true;
thread.Start(socket); #region 该部分实现只适用一个服务器只对应一个客户端 //Task.Run(() => { // string str; // while (true)
// {
// //等待接收客户端连接 Accept返回一个用于和该客户端通信的Socket
// Socket recviceSocket = socket.Accept(); // //Accept()执行过后 当前线程会暂时挂起 只有在有客户端连接时才会继续执行
// richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText(recviceSocket.RemoteEndPoint.ToString() + "已连接" + "\r\n"); })); // //开启接收数据的任务
// Task.Run(() => {
// while (true)
// {
// byte[] buffer = new byte[2048];
// int count;
// //Receive(Byte[]) 从绑定的 Socket 套接字接收数据,将数据存入接收缓冲区。
// //该方法执行过后同上 当前线程会暂时挂起 等到客户端下一次发来数据时继续执行
// count = recviceSocket.Receive(buffer);
// if (count == 0)
// {
// richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText(recviceSocket.RemoteEndPoint.ToString() + "已断开连接" + "\r\n"); })); // break;
// }
// else
// {
// str = Encoding.Default.GetString(buffer, 0, count);
// richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText("收到"+recviceSocket.RemoteEndPoint.ToString()+"数据:" + str + "\r\n"); })); // }
// } // }); // }
//});
#endregion
} /// <summary>
/// 向对应客户端发送数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_send_Click(object sender, EventArgs e)
{
string str = txt_send.Text;
byte[] bytes = new byte[];
bytes = Encoding.Default.GetBytes(str);
//获取combobox的值 从泛型集合中获取对应的客户端socket 然后发送数据
if (cmb_socketlist.Items.Count != )
{
if (cmb_socketlist.SelectedItem == null)
{
MessageBox.Show("请选择一个客户端发送数据!");
return;
}
else
{
socketList[cmb_socketlist.SelectedItem.ToString()].Send(bytes);
}
}
else
{
richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText("当前无连接的客户端" + "\r\n"); }));
}
txt_send.Clear();
} private void DotnetSocketServer_FormClosed(object sender, FormClosedEventArgs e)
{
System.Environment.Exit();
}
}
}
接下来实现SocketClient
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading; namespace DotnetSocketClient
{
public partial class DotnetSocketClient : Form
{
public DotnetSocketClient()
{
InitializeComponent();
}
byte[] buffer = new byte[];
Socket socket;
Thread thread; /// <summary>
/// 连接服务器
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_start_Click(object sender, EventArgs e)
{
try
{
//实例化socket
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//连接服务器
socket.Connect(new IPEndPoint(IPAddress.Parse(txt_ip.Text), int.Parse(txt_port.Text))); thread = new Thread(StartReceive);
thread.IsBackground = true;
thread.Start(socket);
}
catch (Exception ex)
{
SetMessage("服务器异常:" + ex.Message);
} }
/// <summary>
/// 开启接收
/// </summary>
/// <param name="obj"></param>
private void StartReceive(object obj)
{
string str;
while (true)
{
Socket receiveSocket = obj as Socket;
try
{
int result = receiveSocket.Receive(buffer);
if (result == )
{
break;
}
else
{
str = Encoding.Default.GetString(buffer);
SetMessage("接收到服务器数据: " + str);
} }
catch (Exception ex)
{
SetMessage("服务器异常:" + ex.Message); }
} }
/// <summary>
/// 关闭连接
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_close_Click(object sender, EventArgs e)
{
try
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
thread.Abort();
SetMessage("关闭与远程服务器的连接!");
}
catch (Exception ex)
{
SetMessage("异常" + ex.Message);
}
} private void button1_Click(object sender, EventArgs e)
{
socket.Send(Encoding.Default.GetBytes(txt_send.Text));
txt_send.Clear();
}
/// <summary>
/// 添加信息
/// </summary>
/// <param name="msg"></param>
private void SetMessage(string msg)
{
richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText(msg+"\r\n"); }));
}
}
}
接下来测试
因为我们在本地测试,所以使用回环地址为服务的监听地址(127.0.0.1),端口号范围(0~65535)但不能和正在使用的端口号冲突,所以尽量设置大一些的值,本次测试使用端口号 3333,
这里总结一个查看正在使用的端口号的方法:
win+R打开命令提示符,然后输入 netstat -a -n 回车,会列出当前正在使用的协议,内部地址,外部地址和状态
服务器端 输入ip ,输入端口,开启监听 ,客户端输入服务器ip和端口, 点击开始连接
客户端
可以看到,客户端点击连接以后服务器已收到客户端的连接,并作出提示,并且将来访客户端的ip和端口号记录
接下来测试 互相发送数据
服务器给客户端发送数据:
从客户端列选择对应客户端ip,然后从下边textbox 输入要发送的数据,点击发送
服务器:
客户端:
客户端给服务器发送数据:
从客户端的textbox中输入要发送的数据,点击发送
服务器:
客户端
一般情况下,都不会是服务器与客户端一对一的数据交互,接下来 我们借助上边推荐的工具,测试一下多个客户端访问服务器
首先在SocketTool上创建多个客户端,我们可以清楚的看到虽然创建多个客户端,但是端口号都不一样.
然后将这三个客户端全部连接服务器
接下来测试数据交互
三个客户端分别给服务器端发送111,222,333
服务器
服务器选择端口号为7156的客户端发送数据aaaa
服务器
客户端
经过上面测试,简直完美(斜眼笑),果然,每做完一个东西所产生的成就感还是令人心情舒畅啊
原生socket开发实现暂时结束,如果有遗忘的,后续更新补充,
感谢各位客官阅读,拜谢(抱拳~)
接下来还要再写一篇 使用Socket服务器程序框架实现SuperSocket实现服务器
socket通讯的学习,这几篇博客对我帮助很大,书面感谢,我也在此记录一下,说不定以后忘了,在回来看看
C# Socket编程(1)基本的术语和概念
C# Socket编程(2)识别网络主机
C# Socket编程(3)编码和解码
C# Socket编程(4)初识Socket和数据流
C# Socket编程(5)使用TCP Socket
c#Socket服务器与客户端的开发(1)的更多相关文章
- Ajax跨域问题及解决方案 asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS) c#中的Cache缓存技术 C#中的Cookie C#串口扫描枪的简单实现 c#Socket服务器与客户端的开发(2)
Ajax跨域问题及解决方案 目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...
- c#Socket服务器与客户端的开发(2)
上一篇文章我们使用原生的socket分别实现了服务器和客户端, 本篇文章使用SuperSocket来开发实现服务器, 之前也介绍了SuperSocket是一个轻量级, 跨平台而且可扩展的 .Net/M ...
- 异步Socket服务器与客户端
本文灵感来自Andre Azevedo 在CodeProject上面的一片文章,An Asynchronous Socket Server and Client,讲的是异步的Socket通信. S ...
- 一个 Java 的 Socket 服务器和客户端通信的例子
一个 HelloWord 级别的 Java Socket 通信的例子.通讯过程: 先启动 Server 端,进入一个死循环以便一直监听某端口是否有连接请求.然后运行 Client 端,客户端发出连接请 ...
- 最简单的socket服务器与客户端
服务器: //服务器 #include <stdio.h> #include <netinet/in.h> #include <unistd.h> #include ...
- Socket 服务器和客户端通信
//服务器端package com.svse.service; import java.io.BufferedReader; import java.io.IOException; import ja ...
- python简单的socket 服务器和客户端
服务器端代码 if "__main__" == __name__: try: sock = socket.socket(socket.AF_INET, socket.SOCK_ST ...
- 利用ScktSrvr打造多功能Socket服务器
Socket服务端编程中最重要的也是最难处理的工作便是客户请求的处理和数据的接收和发送,如果每一个Socket服务器应用程序的开发都要从头到尾处理这些事情的话,人将会很累,也会浪费大量时间.试想,如果 ...
- socket服务器开发中的SO_REUSEADDR选项与让人心烦的TIME_WAIT
1 发现问题 我在开发一个socket服务器程序并反复调试的时候,发现了一个让人无比心烦的情况:每次kill掉该服务器进程并重新启动的时候,都会出现bind错误:error:98,Address al ...
随机推荐
- 没人看系列----css 随笔
目录 没人看系列----css 随笔 没人看系列----html随笔 前言 没什么要说的就是自己总结,学习用的如果想学点什么东西,请绕行. CSS (Cascading Style Sheets)层叠 ...
- mac上Python多版本共存
http://www.cnblogs.com/mingaixin/p/6295963.html https://www.cnhzz.com/pyenv_virtualenv_virtaulenvwra ...
- 接口和抽象类的区别(JDK1.8)
1.一个类只能进行单继承,但可以实现多个接口. 2.有抽象方法的类一定是抽象类,但是抽象类里面不一定有抽象方法: 接口里面所有的方法的默认修饰符为public abstract,接口里的成员变量默认的 ...
- tarjan算法讲解。
tarjan算法讲解. 全网最详细tarjan算法讲解,我不敢说别的.反正其他tarjan算法讲解,我看了半天才看懂.我写的这个,读完一遍,发现原来tarjan这么简单! tarjan算法,一个关 ...
- GitHub学习笔记:本地操作
安装过程略,假设你已经注册好了Github, 已经有了一个准备好的程序.我们的一切工作都是基于Git Shell,与GUI客户端无关. 在使用前你先要配置好config中的几个内容,主要是你自己的个人 ...
- seek()对中文偏移测试
当前目录下创建"中文测试.txt"文件,写入: 我是大好人aaa我是大坏人bbb f = open('中文测试.txt', 'r+', encoding='utf-8') # f. ...
- servlet什么时候被实例化?【转】
如果没有设置loadOnStartup,则第一次请求的时候实例化 分三种情况:loadOnStartup < 0 即负数的情况下,web容器启动的时候不做实例化处理,servlet首次被调用时做 ...
- ubuntu 16.04安装smatrgitHG工具
SmartGit/HG 是一款开放源代码的.跨平台的.支持 Git 和 Mercurial 的 SVN 图形客户端,可运行在Windows.Linux 和 MAC OS X 系统上. 1.安装 Ubu ...
- 洛谷 P1879 解题报告
P1879 [USACO06NOV]玉米田Corn Fields 题目描述 农场主\(John\)新买了一块长方形的新牧场,这块牧场被划分成\(M\)行\(N\)列\((1 ≤ M ≤ 12; 1 ≤ ...
- Python_文件与文件夹操作
''' os模块除了提供使用操作系统功能和访问文件系统的简便方法之外,还提供了大量文件与文件夹操作的方法. os.path模块提供了大量用于路径判断.切分.连接以及文件夹遍历的方法. shutil模块 ...