首先不多说,最终实现界面如下,可以通过点击启动服务,开启TCP服务器:

开启TCP服务器之后,可以通过点击客户端,打开一个独立的TCP客户端,打开客户端之后,输入正确的IP地址和端口号,可以进行连接服务器,这里可以同时开启多个客户端:

每个客户端连接成功后,服务器的列表中会多出一个EndPoint,连接成功后,服务器和客户端之间就可以自由通话了,可以发送消息,也可以发送文件。

其实这就是QQ等即时通信工具的雏形,如果两个客户端之间需要通信,就通过服务器进行中转。

由于服务器代码量较大,下面上传一下客户端的代码,仅供参考:

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms; namespace MyTCPServer
{
delegate void FileSaveDelegate(byte[] bt,int length); public partial class FrmClient : Form
{
public FrmClient()
{
InitializeComponent(); //委托对象绑定方法
MyShowMsg += ShowMsg; MyFileSave += FileSave;
} //运行标志位
private bool IsRun = true; //创建连接服务器的Socket
Socket sockClient = null; //创建接收服务器消息的线程
Thread thrClient = null; //创建委托对象
ShowMsgDelegate MyShowMsg; FileSaveDelegate MyFileSave; private void btnConnect_Click(object sender, EventArgs e)
{
//获取IP对象
IPAddress address = IPAddress.Parse(this.txtIp.Text.Trim()); //根据IP对象和端口号创建网络节点对象
IPEndPoint endPoint = new IPEndPoint(address, int.Parse(this.txtPort.Text.Trim())); //创建负责连接的套接字,注意其中参数:[IPV4地址,字节流,TCP协议]
sockClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try
{
Invoke(MyShowMsg, "与服务器连接中......");
sockClient.Connect(endPoint);
}
catch (Exception ex)
{
MessageBox.Show("建立连接失败:" + ex.Message, "建立连接");
return;
} Invoke(MyShowMsg, "与服务器连接成功!"); thrClient = new Thread(ReceiveMsg);
thrClient.IsBackground = true;
thrClient.Start(); this.btnConnect.Enabled = false;
} private void FileSave(byte[] arrMsgRec, int length)
{
try
{
SaveFileDialog sfd = new SaveFileDialog(); if (sfd.ShowDialog(this) == DialogResult.OK)
{ string fileSavePath = sfd.FileName;// 获得文件保存的路径;
// 创建文件流,然后根据路径创建文件;
using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))
{
fs.Write(arrMsgRec, , length - );
Invoke(MyShowMsg, "文件保存成功:" + fileSavePath);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
} } private void ReceiveMsg()
{
while(IsRun)
{
// 定义一个2M的缓存区
byte[] arrMsgRec = new byte[ * * ]; // 将接受到的数据存入到输入 arrMsgRec中
int length = -;
try
{
length = sockClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
}
catch (SocketException)
{
return;
}
catch (Exception e)
{
Invoke(MyShowMsg, "连接断开:" + e.Message);
return;
}
if (arrMsgRec[] == ) // 表示接收到的是消息数据;
{
string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, , length - );// 将接受到的字节数据转化成字符串;
Invoke(MyShowMsg, strMsg);
}
if (arrMsgRec[] == ) // 表示接收到的是文件数据;
{
Invoke(MyFileSave, arrMsgRec, length);
}
}
} private void ShowMsg(string str)
{
txtMsg?.AppendText(str + Environment.NewLine);
} private void btnSend_Click(object sender, EventArgs e)
{
string strMsg = txt_Name.Text.Trim() + Environment.NewLine + " -->" + txtMsgSend.Text.Trim() + Environment.NewLine;
byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
byte[] arrSendMsg = new byte[arrMsg.Length + ];
arrSendMsg[] = ; // 用来表示发送的是消息数据
Buffer.BlockCopy(arrMsg, , arrSendMsg, , arrMsg.Length);
sockClient.Send(arrSendMsg); // 发送消息;
Invoke(MyShowMsg, strMsg);
txtMsgSend.Clear();
} private void btnSendFile_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txtSelectFile.Text))
{
MessageBox.Show("请选择要发送的文件!!!");
}
else
{
// 用文件流打开用户要发送的文件;
using (FileStream fs = new FileStream(txtSelectFile.Text, FileMode.Open))
{
//在发送文件以前先给好友发送这个文件的名字+扩展名,方便后面的保存操作;
string fileName = System.IO.Path.GetFileName(txtSelectFile.Text);
string fileExtension = System.IO.Path.GetExtension(txtSelectFile.Text);
string strMsg = "发送的文件为: " + fileName + Environment.NewLine;
byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
byte[] arrSendMsg = new byte[arrMsg.Length + ];
arrSendMsg[] = ; // 用来表示发送的是消息数据
Buffer.BlockCopy(arrMsg, , arrSendMsg, , arrMsg.Length);
sockClient.Send(arrSendMsg); // 发送消息; byte[] arrFile = new byte[ * * ];
int length = fs.Read(arrFile, , arrFile.Length); // 将文件中的数据读到arrFile数组中;
byte[] arrFileSend = new byte[length + ];
arrFileSend[] = ; // 用来表示发送的是文件数据;
Buffer.BlockCopy(arrFile, , arrFileSend, , length);
// 还有一个 CopyTo的方法,但是在这里不适合; 当然还可以用for循环自己转化;
sockClient.Send(arrFileSend);// 发送数据到服务端;
txtSelectFile.Clear();
}
}
} private void btnSelectFile_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.InitialDirectory = "D:\\";
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
txtSelectFile.Text = ofd.FileName;
}
} private void FrmClient_FormClosing(object sender, FormClosingEventArgs e)
{
IsRun = false;
sockClient?.Close();
}
}
}

 如果大家还有什么不明白的地方,可以关注一下微信公众号:dotNet工控上位机

基于C# Socket实现多人网络聊天室的更多相关文章

  1. Java NIO示例:多人网络聊天室

    一个多客户端聊天室,支持多客户端聊天,有如下功能: 功能1: 客户端通过Java NIO连接到服务端,支持多客户端的连接 功能2:客户端初次连接时,服务端提示输入昵称,如果昵称已经有人使用,提示重新输 ...

  2. Qt NetWork即时通讯网络聊天室(基于TCP)

    本文使用QT的网络模块来创建一个网络聊天室程序,主要包括以下功能: 1.基于TCP的可靠连接(QTcpServer.QTcpSocket) 2.一个服务器,多个客户端 3.服务器接收到某个客户端的请求 ...

  3. 基于Linux的TCP网络聊天室

    1.实验项目名称:基于Linux的TCP网络聊天室 2.实验目的:通过TCP完成多用户群聊和私聊功能. 3.实验过程: 通过socket建立用户连接并传送用户输入的信息,分别来写客户端和服务器端,利用 ...

  4. 基于JQuery+JSP的无数据库无刷新多人在线聊天室

    JQuery是一款非常强大的javascript插件,本文就针对Ajax前台和JSP后台来实现一个无刷新的多人在线聊天室,该实现的数据全部存储在服务端内存里,没有用到数据库,本文会提供所有源程序,需要 ...

  5. php websocket-网页实时聊天之PHP实现websocket(ajax长轮询和websocket都可以时间网络聊天室)

    php websocket-网页实时聊天之PHP实现websocket(ajax长轮询和websocket都可以时间网络聊天室) 一.总结 1.ajax长轮询和websocket都可以时间网络聊天室 ...

  6. Python3 网络通信 网络聊天室 文件传输

    Python3 网络通信 网络聊天室 文件传输 功能描述 该项目将实现一个文字和文件传输的客户端和服务器程序通信应用程序.它将传输和接收视频文件. 文本消息必须通过TCP与服务器通信,而客户端自己用U ...

  7. 基于websocket实现的一个简单的聊天室

    本文是基于websocket写的一个简单的聊天室的例子,可以实现简单的群聊和私聊.是基于websocket的注解方式编写的.(有一个小的缺陷,如果用户名是中文,会乱码,不知如何处理,如有人知道,请告知 ...

  8. 利用socket.io+nodejs打造简单聊天室

    代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...

  9. 12、android socket使用demo:网络聊天

    目录: 一.效果图 二.原代码分享 三.代码分析 四.总结 一.效果图如下: 客户端1: 客户端2:           二.原代码分享如下: 1.java代码只有一个 MainActivity.ja ...

随机推荐

  1. @configuration和@component之间的区别

    @configuration和@component之间的区别是:@Component注解的范围最广,所有类都可以注解,但是@Configuration注解一般注解在这样的类上:这个类里面有@Value ...

  2. vs2010 SetUp 安装软件时,界面出现乱码的问题

    AppLocale在简体中文系统里使用之后, 会令某些简体中文的MSI形式的安装程序 显示乱码(比如: OFFICE2000简体中文版安装程序). 解决方法: 方法一: 卸载AppLocale即可解决 ...

  3. spring整合mybatis(代理的方式)【我】

    创建项目等同上一篇非代理方式随笔,只说不一样的部分: 项目结构主要是多了下面红框部分: 配置文件: 主要是dao配置文件中多了Mapper代理java类的扫描包路径: applicationConte ...

  4. rsync服务安装使用

    ssh方式与daemon方式有什么大的区别吗?相对来说ssh比较简单易理解,是不是daemon安全性比较高呢? 区别是:ssh方式是通过ssh协议来传输,需要知道对方机器的用户名和密码. daemon ...

  5. 解决 nw 报错 net::ERR_UNSAFE_PORT

    今天 nw 应用里面的前端请求突然不发送了,也没有异常的信息,后来换上开发版 nw 立刻就发现了报错:   net::ERR_UNSAFE_PORT   这个错误的意思很明显,就是请求的 http 端 ...

  6. gin框架教程:代码系列demo地址

    gin框架教程代码地址: https://github.com/jiujuan/gin-tutorial demo目录: 01quickstart 02parameter 03route 04midd ...

  7. @autowired、@Qualifier、@Primary注解

    @autowired 可以自动帮你把Bean里面引用的对象的setter/getter方法省略,自动帮你set/get. 启动spring IoC时,容器自动装载了一个AutowiredAnnotat ...

  8. 【JulyEdu-Python基础】第 6 课:高级面向对象

    使用@property添加属性和自定义属性 __slots__和property 方法和属性的动态绑定 使用__slots__限定class实例能添加的属性 __slots__仅对当前类实例起作用,对 ...

  9. Leetcode之广度优先搜索(BFS)专题-994. 腐烂的橘子(Rotting Oranges)

    Leetcode之广度优先搜索(BFS)专题-994. 腐烂的橘子(Rotting Oranges) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ar ...

  10. VirtualBox下Centos6.8网络配置

    win10环境下,VirtualBox和Centos6.8已经按照完毕,下面配置Centos6.8网络. 1.设置VirtualBox为桥接模式,具体的有三种联网方法,我们参考http://www.c ...