【总结】学习Socket编写的聊天室小程序
1.前言
在学习Socket之前,先来学习点网络相关的知识吧,自己学习过程中的一些总结,Socket是一门很高深的学问,本文只是Socket一些最基础的东西,大神请自觉绕路。
传输协议
第一次握手:客户端尝试连接服务器,向服务器发送syn包(同步序列编号Synchronize Sequence Numbers),syn=j,客户端进入SYN_SEND状态等待服务器确认
第二次握手:服务器接收客户端syn包并确认(ack=j+1),同时向客户端发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态
第三次握手:第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手
TCP协议:就好比两个电话机 通过电话线进行数据交互的格式约定
HTTP协议:就好比两个人 通过电话机 说话的语法。
(1)公认端口(WellKnownPorts):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80端口实际上总是HTTP通讯。
(2)注册端口(RegisteredPorts):从1024到49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。
(3)动态和/或私有端口(Dynamicand/orPrivatePorts):从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口。
OSI网络7层模型
是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低
是一种无连接的Socket,对应于无连接的UDP服务应用.不安全(丢失,顺序混乱,在接收端要分析重排及要求重发),但效率高.
2.聊天室原理
3.聊天室代码
服务器端代码:
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; namespace Server
{
using System.Net.Sockets;
using System.Net;
using System.Threading;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}
//服务端 监听套接字
Socket socketWatch = null;
//服务端 监听线程
Thread threadWatch = null;
//字典集合:保存 通信套接字
Dictionary<string, Socket> dictCon = new Dictionary<string, Socket>();
private void btnStartListen_Click(object sender, EventArgs e)
{ try
{
//1.创建监听套接字 使用 ip4协议,流式传输,TCP连接
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.绑定端口
//2.1获取网络节点对象
IPAddress address = IPAddress.Parse(txtIP.Text);
IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text));
//2.2绑定端口(其实内部 就向系统的 端口表中 注册 了一个端口,并指定了当前程序句柄)
socketWatch.Bind(endPoint);
//2.3设置监听队列
socketWatch.Listen();
//2.4开始监听,调用监听线程 执行 监听套接字的 监听方法
threadWatch = new Thread(WatchConnecting);
threadWatch.IsBackground = true;
threadWatch.Start();
ShowMsg("枫伶忆,服务器启动啦!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
throw;
} }
void WatchConnecting()
{
//2.4开始监听:此方法会阻断当前线程,直到有 其它程序 连接过来,才执行完毕
Socket sokMsg = socketWatch.Accept();
//将当前连接成功的 【与客户端通信的套接字】 的 标识 保存起来,并显示到 列表中
//将 远程客户端的 ip和端口 字符串 存入 列表
this.lbOnline.Items.Add(sokMsg.RemoteEndPoint.ToString());
//将 服务端的通信套接字 存入 字典集合
dictCon.Add(sokMsg.RemoteEndPoint.ToString(), sokMsg); ShowMsg("有客户端连接了!");
//2.5创建 通信线程
Thread thrMsg = new Thread(ReceiveMsg);
thrMsg.IsBackground = true;
thrMsg.Start(sokMsg);
}
void ReceiveMsg(object obj)
{
try
{
Socket sokMsg = obj as Socket;
//3.通信套接字 监听 客户端的 消息
//3.1创建 消息缓存区
byte[] arrMsg = new byte[ * * ];
while (isReceive)
{
//3.2接收客户端的消息 并存入 缓存区,注意:Receive方法也会阻断当前的线程
sokMsg.Receive(arrMsg);
//3.3将接收到的消息 转成 字符串
string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg);
//3.4将消息 显示到 文本框
ShowMsg(strMsg);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
throw;
}
}
void ShowMsg(string strmsg)
{
this.txtShow.AppendText(strmsg + "\r\n");
}
private void btnSend_Click_1(object sender, EventArgs e)
{ string strClient = this.lbOnline.Text;
if (string.IsNullOrEmpty(strClient))
{
MessageBox.Show("请选择你要发送消息的客户端");
return;
}
if (dictCon.ContainsKey(strClient))
{
string strMsg = this.txtInput.Text.Trim();
ShowMsg("\r\n向客户端【" + strClient + "】说:" + strMsg); //使用 指定的 通信套接字 将 字符串 发送到 指定的客户端
byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
dictCon[strClient].Send(arrMsg);
}
this.txtInput.Text = "";
}
} }
客户端代码:
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; namespace Client
{
using System.Net.Sockets;
using System.Net;
using System.Threading;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}
//客户端 通信套接字
Socket socketMsg = null;
//客户端 通信线程
Thread threadMsg = null; bool isRec = true;//标记任务
private void btnConnect_Click(object sender, EventArgs e)
{
try
{
//1.创建监听套接字 使用 ip4协议,流式传输,TCP连接
socketMsg = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.获取要连接的服务端 节点
//2.1获取网络节点对象
IPAddress address = IPAddress.Parse(txtIP.Text);
IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text));
//3.向服务端 发送链接请求
socketMsg.Connect(endPoint);
ShowMsg("连接服务器成功~~!");
//4.开启通信线程
threadMsg = new Thread(RecevieMsg);
threadMsg.IsBackground = true;
threadMsg.Start();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
throw;
} }
void RecevieMsg()
{
try
{
//3.1创建 消息缓存区
byte[] arrMsg = new byte[ * * ];
while (isRec)
{
socketMsg.Receive(arrMsg);
string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg);
ShowMsg("\r\n服务器说:" + strMsg);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
throw;
}
}
private void btnSend_Click_1(object sender, EventArgs e)
{
string strMsg = this.txtInput.Text.Trim();
byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
socketMsg.Send(arrMsg);
this.txtInput.Text = "";
}
void ShowMsg(string strmsg)
{
this.txtShow.AppendText(strmsg + "\r\n");
}
}
}
最终的效果图如下:
4.注意
至少要定义一个要连接的远程主机的IP和端口号。
服务端先绑定:serverWelcomeSocket.Bind(endp)
客户端再连接:clientSocket.Connect(endp)
每个Socket对象只能一台远程主机连接. 如果你想连接到多台远程主机, 你必须创建多个Socket对象
5.扩展
比如Socket的分包,黏包问题,异步编程在后续的文章继续讨论
【总结】学习Socket编写的聊天室小程序的更多相关文章
- 微信小程序--聊天室小程序(云开发)
微信小程序 -- 聊天室小程序(云开发) 从微信小程序开发社区更新watch接口之后,一直在构思这个项目.项目已经完成很久,但是一直都没有空写一篇博客记录展示一下. 开源地址 wx-cloud-im: ...
- 编写第一个微信小程序界面
编写第一个微信小程序界面 不忘初心,方得始终:初心易得,始终难守. 传统的 web 结构 小程序文件目录结构 小程序页面层级结构 编写第一个小程序 1. 创建小程序目录结构 2. 编写代码 welco ...
- 搭建Spring开发环境并编写第一个Spring小程序
搭建Spring开发环境并编写第一个Spring小程序 2015-05-27 0个评论 来源:茕夜 收藏 我要投稿 一.前面,我写了一篇Spring框架的基础知识文章,里面没 ...
- Socket.io官方聊天室DEMO的学习笔记
照着Socket.io官方的聊天室代码敲了一遍,遇到了一个奇怪的问题: 每次点击SEND按钮的时候,都会重新刷新页面. 在点击页面的一瞬间,看到了正在加载jquery的提示, 然后以为是jquery用 ...
- linux下使用多线程编写的聊天室
自从开始学linux网络编程后就想写个聊天室,一开始原本打算用多进程的方式来写,可是发觉进程间的通信有点麻烦,而且开销也大,后来想用多线程能不能实现呢,于是便去看了一下linux里线程的用法,实际上只 ...
- node.js + socket.io实现聊天室一
前段时间,公司打算在社区做一个聊天室.决定让我来做.本小白第一次做聊天类功能,当时还想着通过ajax请求来实现.经过经理提示,说试试当前流行的node.js 和socket.io来做.于是就上网学习研 ...
- 使用 Socket.IO 开发聊天室
前言 Socket.IO 是一个用来实现实时双向通信的框架,其本质是基于 WebSocket 技术. 我们首先来聊聊 WebSocket 技术,先设想这么一个场景: · 用户小A,打开了某个网站的充值 ...
- Python Socket 编程——聊天室示例程序
上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...
- 使用socket.io搭建聊天室
最近在学习nodejs,需要找一些项目练练手.找来找去发现了一个聊天室的教程,足够简单,也能从中学到一些东西.下面记录我练习过程中待一些笔记. nodeJS模块 共用到了2个模块,express和so ...
随机推荐
- Solr 参考资料
solr 的入门好资料 https://cwiki.apache.org/confluence/display/solr/Apache+Solr+Reference+Guide https://two ...
- Ubuntu文本编辑时vi和nano命令的区别(建议使用nano)
vi是Unix世界里极为普遍的全荧幕文书编辑器,几乎可以说任何一台Unix机器都会提供这套软体就像windows的记事本一样. 键入 vi /etc/hosts 进入vi界面,把光标移动到文件未尾.按 ...
- [转]ionic项目之上传下载数据
本文转自:http://blog.csdn.net/superjunjin/article/details/44158567 一,首先是上传数据 记得在angularjs的controller中注入$ ...
- (转)u3d设计模式
Unity3d中UI开发的MVC模式 ,和游戏开发的其他模块类似,UI一般需要通过多次迭代开发,直到用户体验近似OK.另外至关重要的是, 我们想尽快加速迭代的过程.使用MVC模式来进行设计,已经被业界 ...
- 解决WordPress后台安装主题、插件图片不显示的问题
今天搭建wordpress发现现在主题的时候预览图片都没有了,于是搜索了一下,发现下面的这个方法确实管用,于是转载收藏. 有在WordPress后台安装主题.插件的小伙伴可能会遇到主题.插件图片不显示 ...
- C# 读取Excel
直接添代码: public void connExcel(string strPath) { //string strConn = @"Provider=Microsoft.Jet.OLED ...
- Javascript中的对象和原型(3)
在Javascript中的对象和原型(二)中我们提到,用构造函数创建的对象里面,每个对象之间都是独立的,这样就会降低系统资源的利用率,解决这样问题,我们就要用到下面提到的原型对象. 一 原型对象 原型 ...
- android stuio eclipse映射下的快捷键
转:关于 android stuio eclipse映射下的快捷键 http://www.cnblogs.com/0616--ataozhijia/p/3870064.html 会持续更新)这边讲的常 ...
- Mybaits学习总结2
http://www.cnblogs.com/xdp-gacl/p/4262895.html 继续参考这篇文章写Mybaits学习总结 上一章,我修改了编码,统一为UTF8之后,便没有编码错误 < ...
- 一些MEL命令
这几天写maya脚本,发现一些新命令: 动画命令 cutKey 剪切某段动画曲线 simplify 简化某段曲线 基本命令 getAttr -size 数组属性名 获得数组属性的元素个数 ...