C# Socket实现聊天通信

下面这个实例是一个完整的使用Socket实现的聊天(只限于局域网,如果能提供一个高权限的IP就可以实现类似QQ聊天),其中的原理是:首先开启服务端,打开侦听(任何端口为6600的IP),下面实现的代码:服务端+客户端【VS2005 C#.NET 2.0】

【服务端】{三个窗体:About.cs,ServerMain.cs,Set.cs}:

(ServerMain.cs窗体代码)

using System;

using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Xml;

namespace Server
{
    public partial class ServerMain : Form
    {
        public ServerMain()
        {
            InitializeComponent();
        }

private void ServerMain_Load(object sender, EventArgs e)
        {
            this.CmdStar.Enabled = true;
            this.CmdStop.Enabled = false;
        }

private void 配置参数ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Set TSet = new Set();
            TSet.ShowDialog();
        }

private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            About TAbout = new About();
            TAbout.Show();
        }
        /// <summary>
        /// 获得XML文件中的端口号
        /// </summary>
        /// <returns></returns>
        private int GetPort()
        {
            try
            {
                XmlDocument TDoc = new XmlDocument();
                TDoc.Load("Settings.xml");
                string TPort = TDoc.GetElementsByTagName("ServerPort")[0].InnerXml;
                return Convert.ToInt32(TPort);

}
            catch { return 6600; }//默认是6600
        }

//声明将要用到的类
        private IPEndPoint ServerInfo;//存放服务器的IP和端口信息
        private Socket ServerSocket;//服务端运行的SOCKET
        private Thread ServerThread;//服务端运行的线程
        private Socket[] ClientSocket;//为客户端建立的SOCKET连接
        private int ClientNumb;//存放客户端数量
        private byte[] MsgBuffer;//存放消息数据

private void CmdStar_Click(object sender, EventArgs e)
        {
            ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //提供一个 IP 地址,指示服务器应侦听所有网络接口上的客户端活动
            IPAddress ip = IPAddress.Any;
            ServerInfo=new IPEndPoint(ip,this.GetPort());
            ServerSocket.Bind(ServerInfo);//将SOCKET接口和IP端口绑定
            ServerSocket.Listen(10);//开始监听,并且挂起数为10

ClientSocket = new Socket[65535];//为客户端提供连接个数
            MsgBuffer = new byte[65535];//消息数据大小
            ClientNumb = 0;//数量从0开始统计

ServerThread = new Thread(new ThreadStart(RecieveAccept));//将接受客户端连接的方法委托给线程
            ServerThread.Start();//线程开始运行

CheckForIllegalCrossThreadCalls = false;//不捕获对错误线程的调用

this.CmdStar.Enabled = false;
            this.CmdStop.Enabled = true;
            this.StateMsg.Text = "服务正在运行..."+" 运行端口:"+this.GetPort().ToString();
            this.ClientList.Items.Add("服务于 " + DateTime.Now.ToString() + " 开始运行.");
        }
        
        //接受客户端连接的方法
        private void RecieveAccept()
        {
            while (true)
            {
                //Accept 以同步方式从侦听套接字的连接请求队列中提取第一个挂起的连接请求,然后创建并返回新的 Socket。
                //在阻止模式中,Accept 将一直处于阻止状态,直到传入的连接尝试排入队列。连接被接受后,原来的 Socket 继续将传入的连接请求排入队列,直到您关闭它。
                ClientSocket[ClientNumb] = ServerSocket.Accept();
                ClientSocket[ClientNumb].BeginReceive(MsgBuffer, 0, MsgBuffer.Length, SocketFlags.None,
                    new AsyncCallback(RecieveCallBack),ClientSocket[ClientNumb]);
                lock (this.ClientList)
                {
                    this.ClientList.Items.Add(ClientSocket[ClientNumb].RemoteEndPoint.ToString() + " 成功连接服务器.");
                }
                ClientNumb++;
            }
        }

//回发数据给客户端
        private void RecieveCallBack(IAsyncResult AR)
        {
            try
            {
                Socket RSocket = (Socket)AR.AsyncState;
                int REnd = RSocket.EndReceive(AR);
                //对每一个侦听的客户端端口信息进行接收和回发
                for (int i = 0; i < ClientNumb; i++)
                {
                    if (ClientSocket[i].Connected)
                    {
                        //回发数据到客户端
                        ClientSocket[i].Send(MsgBuffer, 0, REnd,SocketFlags.None);
                    }
                    //同时接收客户端回发的数据,用于回发
                    RSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(RecieveCallBack), RSocket);                 
                }
            }
            catch { }

}

private void CmdStop_Click(object sender, EventArgs e)
        {
            ServerThread.Abort();//线程终止
            ServerSocket.Close();//关闭socket

this.CmdStar.Enabled = true;
            this.CmdStop.Enabled = false;
            this.StateMsg.Text = "等待运行...";
            this.ClientList.Items.Add("服务于 " + DateTime.Now.ToString() + " 停止运行.");
        }

private void ServerMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            ServerThread.Abort();//线程终止
            ServerSocket.Close();//关闭SOCKET
            Application.Exit();
        }
    }
}

Set.cs代码

using System;

using System.Text;
using System.Windows.Forms;

using System.Xml;

namespace Server
{
    public partial class Set : Form
    {
        public Set()
        {
            InitializeComponent();
        }

private void Set_Load(object sender, EventArgs e)
        {
            this.GetAllIP();
            this.GetPort();
        }

private void GetAllIP()
        {

}

private void GetPort()
        {
            try
            {
                XmlDocument TDoc = new XmlDocument();
                TDoc.Load("Settings.xml");
                string TPort = TDoc.GetElementsByTagName("ServerPort")[0].InnerXml;
                this.Port.Text = TPort;

}
            catch { }
        }

private void CmdSave_Click(object sender, EventArgs e)
        {
            try
            {
                XmlDocument TDoc = new XmlDocument();
                TDoc.Load("Settings.xml");

XmlElement Root = TDoc.DocumentElement;
                XmlElement newElem = TDoc.CreateElement("ServerPort");
                newElem.InnerXml = this.Port.Text;

Root.ReplaceChild(newElem, Root.LastChild);

TDoc.Save("Settings.xml");

MessageBox.Show("参数保存成功!");
                this.Close();
            }
            catch
            {
                MessageBox.Show("参数写入XML文件不成功!");
            }

}
    }
}

【客户端代码】{ClientMain.cs窗体}

using System;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;

namespace Client
{
    public partial class ClientMain : Form
    {
        public ClientMain()
        {
            InitializeComponent();
        }

private IPEndPoint ServerInfo;
        private Socket ClientSocket;
        //信息接收缓存
        private Byte[] MsgBuffer;
        //信息发送存储
        private Byte[] MsgSend;

private void ClientMain_Load(object sender, EventArgs e)
        {
            this.CmdSend.Enabled = false;
            this.CmdExit.Enabled = false;
            //定义一个IPV4,TCP模式的Socket
            ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            MsgBuffer = new Byte[65535];
            MsgSend = new Byte[65535];
            //允许子线程刷新数据
            CheckForIllegalCrossThreadCalls = false;
            this.UserName.Text =Environment.MachineName;
        }

private void CmdEnter_Click(object sender, EventArgs e)
        {
            //服务端IP和端口信息设定,这里的IP可以是127.0.0.1,可以是本机局域网IP,也可以是本机网络IP
            ServerInfo = new IPEndPoint(IPAddress.Parse(this.ServerIP.Text), Convert.ToInt32(this.ServerPort.Text));

try
            {
                //客户端连接服务端指定IP端口,Sockket
                ClientSocket.Connect(ServerInfo);
                //将用户登录信息发送至服务器,由此可以让其他客户端获知
                ClientSocket.Send(Encoding.Unicode.GetBytes("用户: " + this.UserName.Text + " 进入系统!\n"));
                //开始从连接的Socket异步读取数据。接收来自服务器,其他客户端转发来的信息
                //AsyncCallback引用在异步操作完成时调用的回调方法
                ClientSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), null);

this.SysMsg.Text += "登录服务器成功!\n";
                this.CmdSend.Enabled = true;
                this.CmdEnter.Enabled = false;
                this.CmdExit.Enabled = true;
            }
            catch
            {
                MessageBox.Show("登录服务器失败,请确认服务器是否正常工作!");
            }
        }

private void ReceiveCallBack(IAsyncResult AR)
        {
            try
            {
                //结束挂起的异步读取,返回接收到的字节数。 AR,它存储此异步操作的状态信息以及所有用户定义数据
                int REnd = ClientSocket.EndReceive(AR);

lock (this.RecieveMsg)
                {
                    this.RecieveMsg.AppendText(Encoding.Unicode.GetString(MsgBuffer, 0, REnd));
                }
                ClientSocket.BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);

}
            catch
            {
                MessageBox.Show("已经与服务器断开连接!");
                this.Close();
            }

}
        //点击发送之后没有直接添加到信息列表中,而是传到服务器,由服务器转发给每个客户端
        private void CmdSend_Click(object sender, EventArgs e)
        {
           
            MsgSend = Encoding.Unicode.GetBytes(this.UserName.Text + "说:\n" + this.SendMsg.Text + "\n");
            if (ClientSocket.Connected)
            {
                //将数据发送到连接的 System.Net.Sockets.Socket。
                ClientSocket.Send(MsgSend);
                this.SendMsg.Text = "";
              
            }
            else
            {
                MessageBox.Show("当前与服务器断开连接,无法发送信息!");
            }
        }

private void CmdExit_Click(object sender, EventArgs e)
        {
            if (ClientSocket.Connected)
            {
                ClientSocket.Send(Encoding.Unicode.GetBytes(this.UserName.Text + "离开了房间!\n"));
                //禁用发送和接受
                ClientSocket.Shutdown(SocketShutdown.Both);
                //关闭套接字,不允许重用
                ClientSocket.Disconnect(false);
            }
            ClientSocket.Close();

this.CmdSend.Enabled = false;
            this.CmdEnter.Enabled = true;
            this.CmdExit.Enabled = false;
        }

private void RecieveMsg_TextChanged(object sender, EventArgs e)
        {
            this.RecieveMsg.ScrollToCaret();
        }

private void SendMsg_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyValue == 13)
            {
                e.Handled = true;
                this.CmdSend_Click(this, null);             
            }
        }
    }
}

下面是该项目的效果图:

1.项目结构图:

服务端:

客户端效果如下:

1。

2。


转载于:https://www.cnblogs.com/8090sns/archive/2012/07/17/Socket.html

C# Socket实现聊天通信相关推荐

  1. LINUX下UDP实现消息镜像通信,linux环境下基于udp socket简单聊天通信

    客户端代码:client.c /* * File: main.c * Author: guanyy * * Created on 20161202 * * 主要实现:客户端和服务端相互通信 */ #i ...

  2. Android聊天软件的开发(七)--聊天通信

    聊天通信通过Socket实现,大概的框架如下图: 通信流程: 1.服务器在启动时开启聊天服务线程 可以通过ServletContextListener监听Servlet的初始化和销毁,来开启和关闭聊天 ...

  3. Android聊天软件的开发--聊天通信

    Android聊天软件的开发(七)--聊天通信 2014-06-20 23:17:49CSDN-vaintwyt-点击数:338  聊天通信通过Socket实现,大概的框架如下图: 通信流程: 1.服 ...

  4. EChat(简易聊天项目)八、Socket实现即时通信(包括部分修改)

    利用Socket实现即时通信 在MyEclipse中写Server端 工程结构如图 SocketMessage.java 该类是一个消息类,用于表示消息是由谁发给谁的.消息内容是什么.接收时间是多少, ...

  5. asp.core api 通过socket和服务器通信发送udp_python socket之TCP/UDP

    #coding=utf-8 # socket #网络中进程之间通信:网络层的"ip地址"可以唯一标识网络中的主机,而传输层的"协议+端口"可以唯一标识主机中的应 ...

  6. socket补充:通信循环、链接循环、远程操作及黏包现象

    socket补充:通信循环.链接循环.远程操作及黏包现象 socket通信循环 server端: import socketphone = socket.socket(socket.AF_INET,s ...

  7. java socket 工具_java Socket简易聊天工具

    本文实例为大家分享了一款Socket简易聊天工具,希望大家喜欢. 代码运行如图,看起来还不错 服务端 package qiu; import java.awt.BorderLayout; import ...

  8. Android基于UDP的局域网聊天通信

    代码地址如下: http://www.demodashi.com/demo/12057.html 记得把这几点描述好咯:代码实现过程 + 项目文件结构截图 + 演示效果 1. 开发环境 1.1 开发工 ...

  9. Android 基于Socket的聊天室

    原文地址为: Android 基于Socket的聊天室 Socket是TCP/IP协议上的一种通信,在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路.一旦建立了虚拟的网络链路, ...

最新文章

  1. c语言输入学生成绩q退出,哭诉、拜求C语言学生成绩管理系统
  2. python 实现结构树模式显示目录下文件
  3. 2.5.jieba分词工具、Jieba安装、全模式/精确模式、添加自定义词典、关键词抽取、词性标注、词云展示
  4. 机器学习之人脸识别face_recognition使用
  5. linux crontab 怎么用,Linux crontab 如何使用
  6. SpringCloud(3)---最简单的 SpringCloud 教程
  7. html页面枚举 暴力,暴力枚举进程模块(示例代码)
  8. Java命令学习系列(六)——javap
  9. NSThread、Cocoa NSOperation
  10. 时间序列分析:非平稳序列的确定性分析
  11. 面向接口编程思想(的好处)
  12. 新能源汽车电池健康状态及能耗分析
  13. C/C++ 中 int 转 string,string 转 int 的几种方法
  14. 收藏 | 百度、美团 ClickHouse、Flink 干货总结!
  15. QBitmap 单色图片
  16. 近世代数:同构、同态
  17. php中die是什么意思,PHP中die()和exit()有什么区别?
  18. Android flac to wav
  19. windows中 mysql修改密码
  20. python中如何对一个属性或方法进行封装_python学习第20天

热门文章

  1. 推荐一款 最方便的 阅读blog的软件---SharpReader!
  2. windows 下使用composer
  3. 【BZOJ1951】【SDOI2010】古代猪文 Lucas定理、中国剩余定理、exgcd、费马小定理
  4. css 填坑常用代码分享
  5. 青蛙跳台阶问题——剑指offer
  6. matplotlib 模块 画图 例2
  7. 安卓高手之路 图形系统(3 底层SurfceFlinger系统)
  8. 最精准的view,canvas,surface之间的关系
  9. 算法----两数之和
  10. Android基础——框架模式MVC在安卓中的实践