五、网络编程实例:聊天室
首先,我们先新建一个C#项目,并生成一个对话框一个按钮。可以通过这个对话框把接收到的消息显示出来。然后可以通过这个按钮来部署服务器与建立连接:
就先使用这样一个朴实无华的界面,然后按钮下面的逻辑代码其实和前面介绍的就很像了,以下是包含注释的代码实现:
服务器:
namespace SocketServer
{public partial class Form1 : Form{Socket server;Socket accept;public Form1(){InitializeComponent();}private void btnBind_Click(object sender, EventArgs e){Button btn = sender as Button;if (btn.Text == "Bind"){//绑定,启动异步接受连接try{int port = int.Parse(tbPort.Text); //输入端口号IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, port); //注意服务器不用输入IP,直接用IPAddress.Any即可server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //建立套接字server.Bind(endpoint); //服务器socket进行绑定server.Listen(10); //开启监听队列server.BeginAccept(AcceptCallback, server); //用异步方法来开始接受连接请求,并用回调函数 btn.Text = "Close";}catch{ }}else if (btn.Text == "Close"){server.Close();btn.Text = "Bind";}}private void AcceptCallback(IAsyncResult ar){Socket sock = ar.AsyncState as Socket;try{accept = sock.EndAccept(ar);//得到连接套接字accept,这是发起请求的套接字,用于往回发消息StateObject so = new StateObject(accept);this.BeginInvoke(new ThreadStart(() => //通过代理来访问对话框,由于对话框是在主线程建立的,因此需要通过代理访问。{ //有兴趣的读着可以自行了解有关线程的知识 this.tbMsg.AppendText("\t收到连接:" + so.endpoint + "\n");}));accept.BeginReceive(so.buffer, 0, so.buffer.Length, SocketFlags.None, ReceiveCallback, so); //开始接受消息server.BeginAccept(AcceptCallback, server); //重新调用Accept,在回调函数中调用本身,形成死循环,一直在等待请求}}private void ReceiveCallback(IAsyncResult ar){StateObject so = ar.AsyncState as StateObject; //存储连接信息的结构体,定义在下面try{int length = so.sock.EndReceive(ar); //接受信息长度string recvstr = System.Text.Encoding.UTF8.GetString(so.buffer, 0, length); //反编码,从流数据编码回字符串形式this.BeginInvoke(new ThreadStart(() => //同上{this.tbMsg.AppendText(so.endpoint + ":" + recvstr + "\n"); //输出信息}));so.buffer = new byte[1024]; //接受数据的存储信息so.sock.BeginReceive(so.buffer, 0, so.buffer.Length, SocketFlags.None, ReceiveCallback, so); //在回调函数再次调用,形成死循环}}private void btnSend_Click(object sender, EventArgs e) //服务器主动发送聊天信息{if (server != null){byte[] sendbytes = System.Text.Encoding.UTF8.GetBytes(this.tbMsgSend.Text);accept.Send(sendbytes);this.tbMsg.AppendText("我:" + this.tbMsgSend.Text + "\n");this.tbMsgSend.Clear();}} }public class StateObject{public byte[] buffer = new byte[1024];public Socket sock = null;public string endpoint;public StateObject(Socket sock){this.sock = sock;endpoint = sock.RemoteEndPoint.ToString();}}
}
客户端
namespace SocketClient
{public partial class Form1 : Form{Socket client;public Form1(){InitializeComponent();}private void btnConnect_Click(object sender, EventArgs e){int port = int.Parse(tbPort.Text); //输入端口号IPAddress ipaddress = IPAddress.Parse(tbIP.Text); //输入IP地址IPEndPoint endpoint = new IPEndPoint(ipaddress, port); //IP地址与端口号唯一标识主机if (client == null){//开始异步连接client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);client.BeginConnect(endpoint, ConnectCallback, client);}}private void ConnectCallback(IAsyncResult ar) //一部连接回调函数{Socket sock = ar.AsyncState as Socket;try{sock.EndConnect(ar);this.BeginInvoke(new ThreadStart(() => //通过代理来访问对话框,由于对话框是在主线程建立的,因此需要通过代理访问。{ //有兴趣的读着可以自行了解有关线程的知识this.tbMsg.AppendText("\t连接成功:)\n");}));StateObject so = new StateObject(sock); //记录服务器信息,类的定义如下sock.BeginReceive(so.buffer, 0, so.buffer.Length, SocketFlags.None, ReceiveCallback, so); //开始接受信息的异步方法}}private void ReceiveCallback(IAsyncResult ar) //接收消息的回调函数{StateObject so = ar.AsyncState as StateObject;try{int length = so.sock.EndReceive(ar); //取得接受信息长度string recvmsg = System.Text.Encoding.UTF8.GetString(so.buffer, 0, length); //对发送消息进行反编码,从流数据编码回字符串this.BeginInvoke(new ThreadStart(() =>{ this.tbMsg.AppendText(so.remotepoint + ":" + recvmsg + "\n"); //接收消息提示信息}));so.buffer = new byte[1024]; //接收消息的存储空间so.sock.BeginReceive(so.buffer, 0, so.buffer.Length, SocketFlags.None, ReceiveCallback, so); //再次开始接收消息,在回到函数调用产生死循环}}private void btnSend_Click(object sender, EventArgs e) //用户发送信息给服务器{if (client != null){byte[] sendbytes = System.Text.Encoding.UTF8.GetBytes(this.tbMsgSend.Text); //编码,从字符串编码为流数据client.Send(sendbytes); //发送流数据this.tbMsg.AppendText("我:" + this.tbMsgSend.Text + "\n"); //写入文本框this.tbMsgSend.Clear(); }}public class StateObject{public byte[] buffer = new byte[1024];public Socket sock;public string remotepoint;public StateObject(Socket sock){this.sock = sock;this.remotepoint = sock.RemoteEndPoint.ToString();}}
}
这两个简单的程序即可生成相应的exe文件,我们可以打开刚才准备好的腾讯云服务器。而window系统的好处就是可以很自由的使用,例如我可以下载一个QQ然后用QQ把我们的程序发过去,事实上我一直都是这样做的。
程序在本机测试时就可以使用127.0.0.1这个虚拟网络IP地址,这个地址是单机模拟接入互联网的,可以得到如下的运行结果:
可见上面简单的程序的确可以实现两个程序进行交流。现在我们尝试把服务器程序放到我们真正的服务器上,看看效果如何。
如此通过QQ把程序发给自己的小号,然后在服务器上进行部署,同时用客户端程序在本地计算机进行连接:
上图中,左边是远程服务器虚拟机,右边是本地,可以看到通过输入对应服务器的IP地址以及端口号:129.204.252.166:8000可以很好的连接服务器,从而可以进行聊天室功能的简单通话。而在服务器端可以看到在笔者家中的外网IP地址是120.230.131.229,不再是之前的127.0.0.1了,说明我们成功通过外网实现了程序的连接。一个简单的聊天室功能就可以实现了。
五、网络编程实例:聊天室相关推荐
- 网络编程项目(聊天室项目)
一.实现目标 一个在Linux下可以使用的聊天软件,要求至少实现如下功能: 1. 采用Client/Server架构 2. Client A 登陆聊天服务器前,需要注册自己的ID和密码 3. 注册成功 ...
- 网络编程--TCP-qq聊天室
QQ聊天服务器端: # 开发者:Virtuous # 开发版本:1.0 # 开发时间: 2022/9/21 13:05from socket import *s=socket(AF_INET,SOCK ...
- C#网络编程 - 局域网聊天室(UDP)
一:知识预览 TextBox禁止编辑 ComboBox元素的添加 获取本机网卡IPs 多道程序设计(多线程) 二:界面设计 三:通讯逻辑 [知识预览] 1> TextBox禁止编辑 privat ...
- 2016-2017-2 20155322 实验五 网络编程与安全
2016-2017-2 20155322 实验五 网络编程与安全 目录 1. 目录 1.1 实践一 1.2 实践二 1.3 实践二 1.4 实践二 1.5 实践二 2.实验心得与体会 3.PSP(Pe ...
- 20175212童皓桢 实验五 网络编程与安全
20175212童皓桢 实验五 网络编程与安全 实验内容 结对编程,完成网络编程与安全相关内容 实验步骤 任务一 任务一要求: 结对实现中缀表达式转后缀表达式的功能 MyBC.java 结对实现从上面 ...
- SSM(五)基于webSocket的聊天室
SSM(五)基于webSocket的聊天室 前言 不知大家在平时的需求中有没有遇到需要实时处理信息的情况,如站内信,订阅,聊天之类的.在这之前我们通常想到的方法一般都是采用轮训的方式每隔一定的时间向服 ...
- java 网络实验_Java实验五网络编程与安全
实验五 网络编程与安全 实验准备 活动一 两人一组结对编程: 0. 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA 1. 结对实现中缀表达式 ...
- 20165201 实验五 网络编程与安全
##20165201 实验五 网络编程与安全 网络编程与安全-1 实验目的与要求: 两人一组结对编程: 参考http://www.cnblogs.com/rocedu/p/6766748.html#S ...
- 2017-2018-2 20165329 实验五 网络编程与安全
2017-2018-2 20165329 实验五 网络编程与安全 实验报告封面 课程:Java程序设计 班级:1653班 姓名:何佳伟 学号:20165329 指导教师:娄嘉鹏 实验日期:2018年5 ...
- #20175201 实验五 网络编程与安全
一.实验五 网络编程与安全-1 1.实验要求: 两人一组结对编程: (1)参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA : (2)结对实现 ...
最新文章
- thymeleaf : input/select/radio回显
- 《快学 Go 语言》第 7 课 —— 冰糖葫芦串
- bios设置_大白菜U盘启动BIOS设置教程
- kettle于javascript步骤错误处理
- YbtOJ#943-平方约数【莫比乌斯反演,平衡规划】
- 千寻和省cors精度对比_使用中海达RTK实战演示千寻cors账号对比省cors网络,验证其测量效果究竟如何...
- oracle 强制 断开,ORA-01092: ORACLE 例程终止 强行断开连接
- RUNOOB python练习题 35 python print各色字体及背景
- ip地址自动切换器_网络IP切换器IPProviders下载_IPProviders官方版下载1.1.22
- 并发容器(J.U.C)中的集合类
- matlab计算macd_matlab计算MACD指标
- mysql_num_fielfs_mysql_num_fields
- 计算机械效率的公式怎么读,机械效率公式总结
- 并发修改异常ConcurrentModificationException详解
- 好用的飞书版固定资产管理系统
- 利用R语言进行具有周期性的时间序列分析
- 新浪短网址生成java_T.CN短网址 新浪T.CN短网址批量生成工具推荐
- ln(1+x)和ln(1-x)的麦克劳林级数
- Pr:导出设置之元数据
- Java知识点串讲之面向对象简述
热门文章
- 系统架构师论文-论软件开发平台的选择和应用(MIS系统)
- 兰州大学计算机专业保研率,兰州部分高校保研率排名,“兰州大学”保研率竟出乎人意料!...
- 怎么样域名绑定服务器显示成功,域名备案成功后怎么绑定服务器
- Mac系统下Typora配置阿里云图床+上传工具PicGo安装
- go 1.16版本,go get用法介绍
- 我理解的一点股票技术分析
- 【面试】阿里巴巴Java经典面试题整理及答案详解
- 如何制作一个可控制的人体骨骼模型
- Intellj Idea关闭自动更新
- linux下桌面快捷方式无法打开,亲测可用:Linux下桌面快捷方式创建实例