udp实现聊天程序

其实udp不存在客户端和服务端之分。我这里主要区分两个程序。因为有个程序需要指定ip.所以我就就把它叫客户端。客户端会先指定ip。并且异步方法接收消息。一旦受到消息,会交给回调函数处理。

服务端会保存客户端发来的ip和端口。用于回发。服务端也实现异步接收消息的方法。

并且消息显示方面。我用了ManualReSetevent来同步控制窗体的显示。注释写的很清楚。本人还是学生,可能注释理解有错,希望各位指点。

我觉得程序最大的特点就是界面不会卡顿,而且一旦设置好ip,客户端和服务端就能随意发送和收取消息。

我画了个图:左右两边的四个小箭头我主要想说明循环调用;

客户端代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace CHEINGDDDDDDD
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public static Socket udpReceive;//接收对象
        public static Socket udpSend;//发送对象
        public const int udpR_PROT = 9095;
        public const int udpS_PORT = 9096;
        public static byte[] udpReDataBuf;//接收字节数组
        public static byte[] udpSeDataBuf;//发送字节数组
        public static bool setIP = false;//用于判断ip是否正确
        public static EndPoint remoteEP;
        public static IPEndPoint remoteIPEP;
        public static IPAddress remoteIpadress;
        public static int sendLen;
        public static string messageC;//收到消息的字符窜
        public static string messageS;//发送消息的字符窜
        public static int receiveLen;//收到消息的的长度
        public static IntPtr Main_wnd_handle;//窗体句柄
        public static ManualResetEvent close;//同步控制线程结束
        public static ManualResetEvent come;//同步控制线程消息收
        public static ManualResetEvent post;//同步控制线程消息发
        public static ManualResetEvent[] list;
        public const int MESSAGE_SEND = 0x521;//消息常量 发送
        public const int MESSAGE_CON = 0x520;//消息常量 接受
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(
            IntPtr hWnd,
            int Msg,
            int wParam,
            int lParam
            );
        public static void Setdate()//用于数据初始化
        {
            come = new ManualResetEvent(false);
            close = new ManualResetEvent(false);
            post = new ManualResetEvent(false);
            list = new ManualResetEvent[3];
            list[0] = close;//0 线程结束
            list[1] = come;//1 消息到达
            list[2] = post;//2 消息发送
            //初始消息为1k
            udpReDataBuf = new byte[1024];
            udpSeDataBuf = new byte[1024];
            //初始发送的ip地址和端口的封装,会在后面的发送按钮明确ip和端口
            remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
            //用于接收的Socket的绑定,确定的端口
            IPEndPoint iep = new IPEndPoint(IPAddress.Any, udpR_PROT);
            //new Socket收
            udpReceive = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //绑定
            udpReceive.Bind(iep);
            //注意remoteEP是EndPoint型,是抽象类,所以不能new
            remoteEP = (EndPoint)remoteIPEP;
            //BeginReceiveFrom是异步的方法接收消息,注意ref remote ,当有消息来会写入ip地址
            udpReceive.BeginReceiveFrom(udpReDataBuf, 0, 1024, SocketFlags.None, ref remoteEP, ReceiveServerCallback, new object());
            //new Socket 发
            udpSend = new Socket(AddressFamily.InterNetwork,
              SocketType.Dgram, ProtocolType.Udp);
            //工作线程启动
            ThreadStart workStart = new ThreadStart(doing);
            Thread gogo = new Thread(workStart);
            gogo.Start();

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //句柄赋值,初始化函数的运行和线程的启动
            Main_wnd_handle = this.Handle;
            Setdate();
        }
        //窗体消息回调函数。用于同步显示发送消息。
        //消息来就添加到texbox2;消息发送就清空texbox3,同时显示在texbox2
        protected override void DefWndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case MESSAGE_CON:
                    textBox2.AppendText("服务器:" + messageC+"\n");
                    break;
                case MESSAGE_SEND:
                    textBox3.Clear();
                    textBox2.AppendText("客户机:" + messageS + "\n");
                    break;

                default:

                    base.DefWndProc(ref m);
                    break;
            }
        }
        //消息发送按钮 

        private void button1_Click(object sender, EventArgs e)
        {
            remoteIPEP.Address = remoteIpadress;//远程ip
            remoteIPEP.Port = udpS_PORT;//远程端口
            messageS = textBox3.Text;//发送的消息字符串
            udpSeDataBuf = Encoding.UTF8.GetBytes(messageS);//字节窜封装成字节数组
            udpSend.SendTo(udpSeDataBuf, remoteIPEP);//发送
            post.Set();//同步控制窗体显示

        }
        //接收消息的回调函数
        public static void ReceiveServerCallback(IAsyncResult ar)
        {
            try
            {
                //远程ip的写入,字节流转换成字符窜
                EndPoint tmpremoteEP = (EndPoint)remoteIPEP;
                receiveLen = udpReceive.EndReceiveFrom(ar, ref tmpremoteEP);
                messageC = Encoding.UTF8.GetString(udpReDataBuf, 0, receiveLen);
                int len = receiveLen;
                //有消息来同步控制窗体显示
                if (len != 0)
                {
                    come.Set();
                }
                //再次调用异步方法接收
                udpReceive.BeginReceiveFrom(udpReDataBuf, 0, 1024, SocketFlags.None, ref remoteEP, ReceiveServerCallback, new object());

            }
            catch (SocketException se)
            {
                MessageBox.Show(se.Message);
            }

        }
        //工作线程控制窗体显示
        public static void doing()
        {
            int select;
            bool working = true;
            while (working)
            {
                select = WaitHandle.WaitAny(list, 1000);
                switch (select)
                {
                    case 0:
                        working = false;
                        break;
                    case 1:
                        come.Reset();
                        SendMessage(Main_wnd_handle, MESSAGE_CON, 0, 0);
                        //消息到达
                        break;
                    case 2:
                        post.Reset();
                        SendMessage(Main_wnd_handle, MESSAGE_SEND, 0, 0);

                        //消息发送
                        break;
                    case WaitHandle.WaitTimeout:
                        //超时处理
                        break;
                }

            }

        }
        //判断写入的ip是否正确
        private void button2_Click(object sender, EventArgs e)
        {
            setIP = IPAddress.TryParse(textBox1.Text, out remoteIpadress);
            if (!setIP)
            {
                label1.Text = "输入IP不正确";
                textBox1.Focus();

            }
            else
            {
                label1.Text = "IP地址解析正确";

            }
        }
        //结束工作线程

        private void button3_Click(object sender, EventArgs e)
        {
            close.Set();
        }
    }
}

服务端代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Main_wnd_handle = this.Handle;
            Setdate();
        }
        //设置变量
        public const int MESSAGE_CON = 0x520;//消息常亮 收
        public const int MESSAGE_SEND = 0x521;//消息常量 发
        public static IntPtr Main_wnd_handle;//窗体句柄
        public static Socket udpReceive;//socket 收
        public static Socket udpSend;//socket 发
        public const int udpR_PORT = 9096;
        public const int udpS_PORT = 9095;
        public static IPEndPoint remoteIPEP;
        public static EndPoint remoteEP;
        public static byte[] udpSeDataBuf;
        public static byte[] udpReDataBuf;
        public static int receiveLen;
        public static string messageC;
        public static string messageS;
        public static ManualResetEvent post;
        public static ManualResetEvent close;
        public static ManualResetEvent come;
        public static ManualResetEvent[] list;

        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(
            IntPtr hWnd,
            int Msg,
            int wParam,
            int lParam
            );
        //窗体回调处理
        protected override void DefWndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case MESSAGE_CON:
                    textBox1.AppendText("客户机:" + messageC+"\n");
                    break;

                case MESSAGE_SEND:
                    textBox2.Clear();
                    textBox1.AppendText("服务器:" + messageS + "\n");
                    break;
                default:

                    base.DefWndProc(ref m);
                    break;
            }
        }
        public static void Setdate()
        {
            come = new ManualResetEvent(false);
            post = new ManualResetEvent(false);
            close = new ManualResetEvent(false);
            list = new ManualResetEvent[3];
            list[0] = close;
            list[1] = come;
            list[2] = post;
            udpReDataBuf = new byte[1024];
            udpSeDataBuf = new byte[1024];
            remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
            IPEndPoint iep = new IPEndPoint(IPAddress.Any, udpR_PORT);
            udpReceive = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            udpReceive.Bind(iep);
            udpSend = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            remoteEP = (EndPoint)remoteIPEP;
            udpReceive.BeginReceiveFrom(udpReDataBuf, 0, 1024, SocketFlags.None, ref remoteEP, ReceiveServerCallback, new object());

            ThreadStart workStart = new ThreadStart(doing);
            Thread gogo = new Thread(workStart);
            gogo.Start();

        }
        public static void doing()
        {
            bool linlin = true;
            int select;

            while (linlin)
            {
                select = WaitHandle.WaitAny(list, 1000);
                switch (select)
                {
                    case 0:

                        linlin = false;
                        break;
                    case 1:
                        come.Reset();

                        SendMessage(Main_wnd_handle, MESSAGE_CON, 0, 0);

                        break;
                    case 2:
                        post.Reset();
                        SendMessage(Main_wnd_handle, MESSAGE_SEND, 0, 0);
                        break;
                    case WaitHandle.WaitTimeout:

                        break;

                }

            }

        }
        public static void ReceiveServerCallback(IAsyncResult ar)
        {
            try
            {
                //实际写入远程ip的地方,所以需要个临时tmpremoteEP写入。再装换成IPEndPoint类型给remoteIPEP,用于确定会发的ip地址
                EndPoint tmpremoteEP = (EndPoint)remoteIPEP;
                receiveLen = udpReceive.EndReceiveFrom(ar, ref tmpremoteEP);
                remoteIPEP = (IPEndPoint)tmpremoteEP;
                messageC = Encoding.UTF8.GetString(udpReDataBuf, 0, receiveLen);
                if (receiveLen != 0)
                {
                    come.Set();
                }
                udpReceive.BeginReceiveFrom(udpReDataBuf, 0, 1024, SocketFlags.None, ref remoteEP, ReceiveServerCallback, new object());

            }
            catch (SocketException se)
            {
                MessageBox.Show(se.Message);
            }

        }

        private void button1_Click(object sender, EventArgs e)
        {
            messageS = textBox2.Text;
            udpSeDataBuf = Encoding.UTF8.GetBytes(messageS);
            //注意远程端口的绑定
            remoteIPEP.Port = udpS_PORT;
            udpSend.SendTo(udpSeDataBuf, remoteIPEP);
            post.Set();

        }

    }
}

我画了个图:左右两边的四个小箭头我主要想说明循环调用;

时间: 2024-10-25 09:20:46

udp实现聊天程序的相关文章

JAVA实现UDP组播聊天程序

分类: Java 一.实验环境 编程语言:Java1.5(运行在JVM(Java Virsual Machine)) 开发工具:eclipce3.2 测试环境:局域网 二.实验目的 社会已经进入信息时代,网络技术在飞速发展.大量应用都依赖于从一个主机向多个主机或者从多个主机向多个主机发送同一信息的能力,在Internet上分布的数目可能达数十万台,这些都需要更高的带宽,并且大大超出了单播的能力.一种能最大限度地利用现有带宽的重要技术是IP组播. 三.组播聊天程序的实现: /** * 该程序实现了

JAVA学习第六十课 — UDP协议 &基于多线程模拟简单的QQ聊天程序

UDP传输 UDP有发送端和接受端,有两大类,DatagramSocket.DatagramPacket 建立发送端和接收端 建立数据包 调用Socket的接收发送方法 关闭Socket 注意:发送端和接收端是两个独立的运行程序 UDP发送端演示 DatagramPacket(byte[] buf, int length, InetAddress address, int port) 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号. public static voi

TCP、UDP练习题 (UDP聊天程序、TCP上传文本文件和图片文件)

TCP.UDP编程练习 TCP ☆上传文本文件 读取一个本地文本文件,将数据发送到服务端,服务器端对数据进行存储. 存储完毕后,给客户端一个提示. 一.解题思路 客户端:(1) 创建Socket对象----用服务器的ip+端口号 (2)读取文件内容 (3)通过socket把内容发送给服务器端(把socket中的输出流包装成"打印流"来进行发送文本,是一种比较安全的输出方式,不会出现失真.) 服务器端:(1) 创建服务器socket---ServerSocket (2)通过ServerS

Java UDP 多用户 组播 聊天程序

一.实验环境 编程语言:Java1.8(运行在JVM(Java Virsual Machine)) 开发工具:eclipce 测试环境:局域网 二.实验目的 社会已经进入信息时代,网络技术在飞速发展.大量应用都依赖于从一个主机向多个主机或者从多个主机向多个主机发送同一信息的能力,在Internet上分布的数目可能达数十万台,这些都需要更高的带宽,并且大大超出了单播的能力.一种能最大限度地利用现有带宽的重要技术是IP组播. 三.组播聊天程序的实现: package cn.gdut.edu.udp;

UDP—Socket,套接字聊天简单的聊天程序。

思路:(发送端) 1.既然需要聊天.就应该怎么建立聊天程序,,DatagramSocket对象http://www.w3cschool.cc/manual/jdk1.6/ DatagramSocket dgSocket = new DatagramSocket(); 2.那么发给谁?怎么打包数据.DatagramPacket. 代码如下DatagramPacket对象API文档链接http://www.w3cschool.cc/manual/jdk1.6/ 具体查看集体代码: //创建数据包 b

用L脚本语言开发一个简单的局域网聊天程序

#scp #这是一个简单的局域网聊天程序的例子 定义:字符串,string1 定义:字符串,string2 #addr1是对方的地址 #addr2是自己的地址 #如果addr1和addr2相同,就是自己和自己聊天 定义:地址,addr1,127.0.0.1,27015 定义:地址,addr2,127.0.0.1,27015 定义:整数,字节数,0 #在自己的UDP端口上监听 定义:网络连接,conn2,UDP 监听:conn2,addr2 #连接对方的UDP端口 定义:网络连接,conn1,UD

聊天程序(基于Socket、Thread)

聊天程序简述 1.目的:主要是为了阐述Socket,以及应用多线程,本文侧重Socket相关网路编程的阐述.如果您对多线程不了解,大家可以看下我的上一篇博文浅解多线程 . 2.功能:此聊天程序功能实现了服务端跟多个客户端之间的聊天,可以群发消息,选择ip发消息,客户端向服务端发送文件. (例子为WinForm应用程序) Socket,端口,Tcp,UDP. 概念 1.Socket还被称作"套接字",应用程序通常通过套接字向网络发送请求或者应答网络请求.根据连接启动的方式以及本地套接字要

【Java网络编程】基于UDP的聊天通信

使用udp协议,写一个基于命令行的聊天软件:客户端跟服务端分别在命令行启动之后,客户端和服务器端可以互相发送数据. 一.创建线程 sendThread 和receiveThread 1 package com.fhcq.chat; 2 3 //双工的聊天程序 4 //可以发送数据,同时也可以等待接收数据 5 //需要使用多线程来实现 6 7 public class QICQDemo { 8 9 public static void main(String[] args) { 10 // TOD

Java UDP实现聊天功能代码

我以前经常写的是基于TCP的网络编程,由于TCP建立连接鼻血要经过三次握手连接,服务器端需要阻塞式等待客户端的连接.而UDP则是可以直接向目的地址的目的端口上发送数据包,由于它只负责发送出去就好,不管对方是否正确接受到与否,所以当网络性能不好时它容易出现丢包的问题.(注意:UDP是基于数据报为单位进行传输的,而TCP是一种基于流进行传输的) 但是UDP很好的模拟了我们呢平时聊天的方式,可以很好的实现连续多次发送和接受,也就是简单的QQ聊天的功能. 现在来简要介绍Java中有关UDP编程相关的类: