QQ聊天程序的网络通信原理及编程

合集下载

基于TCP、UDP使用C-开发的简易qq

基于TCP、UDP使用C-开发的简易qq

TCP/UDP程序开发使用C#制作简易qqTCP、UDP程序开发一.实验课时8学时二.实验目的开发TCP/UDP协议应用程序,掌握网络应用程序的工作原理。

通过本实验,深入理解TCP和UDP协议的异同点,了解网络协议的工作过程,学会网络通信编程的基本方法,能够编制网络应用程序。

三.实验内容(1)了解和掌握“基于UDP——面向无连接的应用程序”和“基于TCP——面向连接的应用程序”的运行机制和编程方法。

(2)选择以下一个内容,编写一个网络通信应用程序①聊天程序;②邮件收发程序;③HTTP服务器程序。

四.实验要求(1)使用任意编程语言(如Java,C,VB,Delphi等)编写基于TCP或UDP协议的网络应用程序。

(2)总结实验过程,内容包括:方案、程序、调试、结果、分析、结论。

五.实验设备(1)硬件要求:计算机、Internet网。

(2)软件要求:Windows操作系统、相关软件开发工具(如Microsoft Visual Studio,JDK等)。

六.预习要求(1)复习TCP/UDP协议原理。

(2)复习应用进程跨越网络通信的基本编程方法。

(3)复习聊天、邮件、HTTP服务的相关原理。

(4)熟悉相关编程语言及编程工具环境。

七.注意事项(1)遵守实验纪律,爱护实验设备。

(2)提交详细实验报告一份。

实验过程和结果不能简单地复制相关命令或内容,要有理解和分析。

八.程序代码1.服务器端using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using ;using .Sockets;using System.Threading;using System.IO;namespace WindowsFormsApplication1{public partial class Form1 : Form{public Form1(){InitializeComponent();this.Init();tab2.Visible = true;tab3.Visible = false;tab1.Visible = false;}private void btnLog_Click(object sender, EventArgs e){if (txtIP.Text == "" || txtPort.Text == ""){MessageBox.Show("请输入IP地址或端口号!", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);return;}else{try{IPAddress ipadd = IPAddress.Parse(this.txtIP.Text);int port = Convert.ToInt32(this.txtPort.Text);tab3.Visible = true;tab1.Visible = true;this.Init2();this.btnImgFile.Enabled = false;this.Text = "服务器"+ DateTime.Now.ToString() + " "+ DateTime.Now.DayOfWeek.ToString();richTextBox1.AppendText("System:服务器已进入聊天室!?<-"+ DateTime.Now.ToLongTimeString() + "->.....\r\n");string SerIp = txtIP.Text.ToString();string SerPort = txtPort.Text.ToString();labip.Text = " IP地址:" + " " + SerIp + " ";labport.Text = " 端口号:" + " " + SerPort;}catch (Exception){MessageBox.Show("您输入的IP地址或端口号不正确,\n请重新输入!", "错误 ", MessageBoxButtons.OK, MessageBoxIcon.Error);}}}//重置服务器信息private void btnResent_Click_1(object sender, EventArgs e){txtIP.Clear();txtPort.Clear();}private void Init(){richTextBox1.Visible = false;txt1_sendinfo.Visible = false;}private void Init2(){richTextBox1.Visible = true;txt1_sendinfo.Visible = true;}private OpenFileDialog openfiledialog = new OpenFileDialog();private SaveFileDialog savefiledialog = new SaveFileDialog();private byte[] img;//传输图片用字节数组private int imgflag = 0;private FileStream fstream;public delegate void UpdateRichTextBox(string msg);//异步委托代理public delegate void UpdateImg(Stream s);private Socket socket; //服务器端套接字private Socket clientSocket; //客户端连接套接字private Thread thread;//启动服务器,开始监听private void btn_start_Click(object sender, EventArgs e){try{IPAddress ip = IPAddress.Parse(this.txtIP.Text);IPEndPoint server = new IPEndPoint(ip, Int32.Parse(this.txtPort.Text));//创建服务器套接字socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);socket.Bind(server);//绑定端口号socket.Listen(10);thread = new Thread(new ThreadStart(AcceptMessage));thread.Start();//开始监听this.Text = " 服务器Taking....";richTextBox1.Clear();richTextBox1.AppendText("System:服务器已启动!<-"+ DateTime.Now.ToLongTimeString() + "->.....\r\n");btnImgFile.Enabled = true;btn_start.Enabled = false;btn_stop.Enabled = true;}catch (Exception ex){MessageBox.Show("服务器: " + ex.Message);this.btn_start.Enabled = true;}}//接收客户端信息public void AcceptMessage() //异步接收信息后台线程方法{this.clientSocket = socket.Accept();this.richTextBox1.Clear();richTextBox1.AppendText("System:服务器连接成功!?<-"+ DateTime.Now.ToLongTimeString() + "->.....\r\n");while (true){try{if(this.clientSocket == null|| this.clientSocket.Connected == false)break;NetworkStream netStream = new NetworkStream(this.clientSocket);//通过clientSocket对象获取NetworkStream对象//得到一条消息的长度byte[] dataSize = new byte[4];netStream.Read(dataSize, 0, 4);int size = System.BitConverter.ToInt32(dataSize, 0);//循环接收直到一条完整的消息全部读入到字节数组中byte[] message = new byte[size];int dataleft = size;int start = 0;if (size > 0){while (dataleft > 0){int recv = netStream.Read(message, start, dataleft);start += recv;dataleft -= recv;}if (message[0] == 101)//101代表传输图片{MemoryStream ms = new MemoryStream(message, 1, message.Length - 1);richTextBox1.BeginInvoke(new UpdateImg(ViewImg), new object[] { ms });}else//默认进行普通传输{string Msg = System.Text.Encoding.Unicode.GetString(message, 1, message.Length - 1);this.richTextBox1.BeginInvoke(newUpdateRichTextBox(UpdateMessage), new object[] { Msg });}}Thread.Sleep(100);}catch (.Sockets.SocketException se){MessageBox.Show("服务器:" + se.Message);}}}//点击“发送”按钮private void btn_send_Click(object sender, EventArgs e){if (txt1_sendinfo.Text == ""){MessageBox.Show("请先输入内容!");txt1_sendinfo.Clear();txt1_sendinfo.Focus();return;}if (imgflag == 1){//发送图片?byte[] imgSize = new byte[4];//将32位整数值转换为字节数组imgSize = System.BitConverter.GetBytes(img.Length + 1);//其中加1是因为后面了一个101做分隔符try{NetworkStream netStream = new NetworkStream(clientSocket);netStream.Write(imgSize, 0, 4);netStream.WriteByte(101);//分隔符netStream.Write(img, 0, img.Length);netStream.Flush();this.richTextBox1.SelectionColor = Color.SteelBlue;this.richTextBox1.AppendText("服务器<-"+ DateTime.Now.ToLongTimeString() + "->:\r\n");this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length;Clipboard.SetDataObject(Image.FromStream(fstream));richTextBox1.Paste();this.richTextBox1.SelectionColor = Color.SteelBlue;this.richTextBox1.AppendText("\n");fstream.Flush();fstream.Close();//此流必须在这里才可以消除txt1_sendinfo.Paste();this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length;this.richTextBox1.Focus();this.txt1_sendinfo.Text = "";this.txt1_sendinfo.Focus();imgflag = 0;//复原return;//不执行后面的传输文本信息}catch (System.Exception ex){MessageBox.Show("服务器:" + ex.Message);}}//发送文本信息this.richTextBox1.SelectionColor = Color.SteelBlue;string str = "服务器<-"+ DateTime.Now.ToLongTimeString() + "->:\r\n"+ txt1_sendinfo.Text;int i = str.Length;if (i == 0){return;}else{//因为str为Unicode编码,每个字符占2个字节,所以实际字节数应为字符个数*2 i *= 2;}byte[] dataSize = new byte[4];//将32位整数值转换为字节数组dataSize = System.BitConverter.GetBytes(i + 1);//其中加1是因为后面写了一个1做分隔符byte[] sendbytes = System.Text.Encoding.Unicode.GetBytes(str);try{NetworkStream netStream = new NetworkStream(clientSocket);netStream.Write(dataSize, 0, 4);netStream.WriteByte(1);//分隔符netStream.Write(sendbytes, 0, sendbytes.Length);netStream.Flush();richTextBox1.SelectionColor = Color.SteelBlue;this.richTextBox1.AppendText(str + "\n");this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length;this.richTextBox1.Focus();this.txt1_sendinfo.Rtf = "";this.txt1_sendinfo.Focus();}catch (System.Exception ex){MessageBox.Show("服务器:" + ex.Message);}}//断开连接private void btn_stop_Click(object sender, EventArgs e){socket.Close();thread.Abort();thread.Join(10);this.btn_start.Enabled = true;btn_stop.Enabled = false;this.btnImgFile.Enabled = false;this.Text = " 服务器"+ DateTime.Now.ToString() + " "+ DateTime.Now.DayOfWeek.ToString();this.richTextBox1.AppendText("System:服务器断开连接!<-"+ DateTime.Now.ToLongTimeString() + "->..... \r\n");}//接收文本private void UpdateMessage(string strmsg) //将异步接收到的信息显示在文本框里{this.richTextBox1.SelectionColor = Color.LightCoral;this.richTextBox1.AppendText(strmsg + "\n");this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length;this.richTextBox1.Focus();this.txt1_sendinfo.Focus();}//接收图片信息private void ViewImg(Stream s) //将异步接收到的信息显示在文本框里{richTextBox1.SelectionStart = richTextBox1.Text.Length;richTextBox1.SelectionColor = Color.LightCoral;richTextBox1.AppendText("服务器接收图片<-"+ DateTime.Now.ToLongTimeString() + "->:\r\n");Clipboard.SetDataObject(Image.FromStream(s));//利用剪切板richTextBox1.Paste();richTextBox1.SelectionColor = Color.LightCoral;richTextBox1.AppendText("\n");richTextBox1.SelectionStart = richTextBox1.Text.Length;richTextBox1.Focus();txt1_sendinfo.Focus();}//上传图片文件中的图片private void btnImgFile_Click(object sender, EventArgs e){openfiledialog.Filter = "所有文件t(*.*)|*.*|位图文(*.bmp)|*.bmp|文件t (.jpg)|*.jpg|文件t(.gif)|*.gif";if (openfiledialog.ShowDialog() == DialogResult.OK){String strpath = openfiledialog.FileName;fstream = new FileStream(strpath, FileMode.Open);BinaryReader breader = new BinaryReader(fstream);img = breader.ReadBytes((int)fstream.Length);Clipboard.SetDataObject(Image.FromStream(fstream));txt1_sendinfo.Paste();imgflag = 1;}}//退出聊天室private void btn_Exit_Click(object sender, EventArgs e){if (btn_stop.Enabled != true){this.Close();Application.Exit();}else{MessageBox.Show("请先断开连接!");return;}}//取消发送private void btnRest_Click(object sender, EventArgs e){txt1_sendinfo.Clear();}//清屏private void btnClear_Click(object sender, EventArgs e){this.richTextBox1.Clear();}}}2.客户端using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using ;using .Sockets;using System.Threading;using System.IO;namespace WindowsFormsApplication1{public partial class Form1 : Form{public Form1(){InitializeComponent();this.Init();tab2.Visible = true;tab3.Visible = false;tab1.Visible = false;}private void Init(){this.richTextBox1.Visible = false;this.txt2_send.Visible = false;}private void Init2(){this.richTextBox1.Visible = true;this.txt2_send.Visible = true;}//登录聊天室private void btnLog_Click(object sender, EventArgs e){if (txtIP.Text == "" || txtPort.Text == ""){MessageBox.Show("服务器信息不能为空!", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);return;}if (txtName.Text == ""){MessageBox.Show("请输入您的呢称!", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);return;}else{try{IPAddress ipadd = IPAddress.Parse(this.txtIP.Text);int port = Convert.ToInt32(this.txtPort.Text);userName = txtName.Text.ToString();tab1.Visible = true;this.Init2();tab3.Visible = true;this.btnImgFile.Enabled = false;this.Text = " " + userName + " " + DateTime.Now.ToString() + " " + DateTime.Now.DayOfWeek.ToString();richTextBox1.AppendText("System:"+ userName + " 已进入聊天室!<-"+ DateTime.Now.ToLongTimeString() + "->.....\r\n");string SerIp = txtIP.Text.ToString();string SerPort = txtPort.Text.ToString();lbSerIp.Text = " IP地址 :" + " " + SerIp + " ";lbSerPort.Text = " 端口号?:" + " " + SerPort;}catch (Exception){MessageBox.Show("您输入的服务器信息不合法,\n请重新输入!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);}}}//重置服务器信息和昵称private void btnResent_Click(object sender, EventArgs e){txtIP.Clear();txtPort.Clear();txtName.Clear();}private OpenFileDialog openfiledialog = new OpenFileDialog();private SaveFileDialog savefiledialog = new SaveFileDialog();private byte[] img;//保存传图片时的字节数组private int imgflag = 0;private FileStream fstream;public delegate void UpdateMessage(string msg);public delegate void UpdateImg(Stream s);private Socket socket;private Thread thread;public string userName;//与服务器连接private void btn_req_Click(object sender, EventArgs e){try{IPAddress ip = IPAddress.Parse(this.txtIP.Text);IPEndPoint server = new IPEndPoint(ip, Int32.Parse(this.txtPort.Text));//创建客户端套接字socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);socket.Connect(server);//连接thread = new Thread(new ThreadStart(AcceptMessage));thread.Start();this.Text = " " + userName + " Taking....";richTextBox1.Clear();richTextBox1.AppendText("System:" + userName + " 连接到服务器!<-" + DateTime.Now.ToLongTimeString() + "->.....\r\n");btn_req.Enabled = false;btn_close.Enabled = true;btnImgFile.Enabled = true;}catch{richTextBox1.Clear();richTextBox1.AppendText("System:" + userName + " 未连接上服务器!<-" + DateTime.Now.ToLongTimeString() + "->.....\r\n");return;}}//接收后台接收消息public void AcceptMessage() //异步接收信息后台线程方法{while (true){try{if (this.socket == null || this.socket.Connected == false){richTextBox1.Clear();richTextBox1.AppendText("System:" + userName + "未连接上服务器!<-" + DateTime.Now.ToLongTimeString() + "->.....\r\n");break;}NetworkStream netStream = new NetworkStream(this.socket);//必须放在if后,this.socket可能没实例化//得到一条消息的长度byte[] dataSize = new byte[4];//前4字节代表后面字节总数,发送时骸已经处理过了try{netStream.Read(dataSize, 0, 4);}catch (Exception){}int size = System.BitConverter.ToInt32(dataSize, 0);//循环接收直到一条完整的消息全部读入到字节数组中byte[] message = new byte[size];int dataleft = size;int start = 0;while (dataleft > 0){int recv = netStream.Read(message, start, dataleft);start += recv;dataleft -= recv;}if (message[0] == 101)//101代表传输图片{MemoryStream ms = new MemoryStream(message, 1, message.Length - 1); richTextBox1.BeginInvoke(new UpdateImg(ViewImg), new object[] { ms });}else//默认进行普通传输{string Msg = System.Text.Encoding.Unicode.GetString(message, 1, message.Length - 1);richTextBox1.BeginInvoke(new UpdateMessage(ViewMessage), new object[] { Msg });}Thread.Sleep(100);}catch (.Sockets.SocketException ex){MessageBox.Show(userName + ":" + ex.Message);}}}//传输文件private void ViewMessage(string msg){richTextBox1.SelectionColor = Color.SteelBlue;richTextBox1.AppendText(msg + "\n");richTextBox1.SelectionStart = richTextBox1.Text.Length;//定位到最后,保持最新消息可见richTextBox1.Focus();txt2_send.Focus();}//接收图片信息private void ViewImg(Stream s){richTextBox1.SelectionStart = richTextBox1.Text.Length;richTextBox1.SelectionColor = Color.SteelBlue;richTextBox1.AppendText(userName + "接收图片<-"+ DateTime.Now.ToLongTimeString() + "->:\r\n");Clipboard.SetDataObject(Image.FromStream(s));//利用剪切板richTextBox1.Paste();richTextBox1.SelectionColor = Color.SteelBlue;richTextBox1.AppendText("\n");richTextBox1.SelectionStart = richTextBox1.Text.Length;richTextBox1.Focus();txt2_send.Focus();}//点击发送按钮private void btn_send_Click(object sender, EventArgs e){if (txt2_send.Text == ""){MessageBox.Show("请先输入内容!");txt2_send.Clear();txt2_send.Focus();return;}if (imgflag == 1)//imgflag的值在方法tnImgFile_Click中可能改变{//当传输图片时byte[] imgSize = new byte[4];//将32位整数值转换为字节数组imgSize = System.BitConverter.GetBytes(img.Length + 1);//后面一个标识数:101try{NetworkStream netStream = new NetworkStream(this.socket);netStream.Write(imgSize, 0, 4);netStream.WriteByte(101);//标识数netStream.Write(img, 0, img.Length);netStream.Flush();this.richTextBox1.SelectionColor = Color.LightCoral;this.richTextBox1.AppendText(userName + "<-"+ DateTime.Now.ToLongTimeString() + "->:\r\n");this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length;Clipboard.SetDataObject(Image.FromStream(fstream));richTextBox1.Paste();richTextBox1.SelectionColor = Color.LightCoral;this.richTextBox1.AppendText("\n");fstream.Flush();fstream.Close();//此流必须在这里才可以消除txt2_send.Paste();this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length;this.richTextBox1.Focus();this.txt2_send.Text = "";this.txt2_send.Focus();imgflag = 0;//复原return;//不执行后面的传输文本信息}catch (System.Exception ex){MessageBox.Show("服务器:" + ex.Message);}}//发送文本信息时this.richTextBox1.SelectionColor = Color.LightCoral;string str = userName + "<-" + DateTime.Now.ToLongTimeString() + "->:阰\r\n" + txt2_send.Text;int i = str.Length;if (i == 0){return;}else{//因为str为Unicode编码,每个字符占2个字节,所以实际字节数应为字符个数*2 i *= 2;}byte[] dataSize = new byte[4];//将32位整数值转换为字节数组dataSize = System.BitConverter.GetBytes(i + 1);//后面一个标识数:1 byte[] sendbytes = System.Text.Encoding.Unicode.GetBytes(str);try{NetworkStream netStream = new NetworkStream(this.socket);netStream.Write(dataSize, 0, 4);netStream.WriteByte(1);//标识数netStream.Write(sendbytes, 0, sendbytes.Length);netStream.Flush();richTextBox1.SelectionColor = Color.LightCoral;this.richTextBox1.AppendText(str + "\n");richTextBox1.SelectionStart = richTextBox1.Text.Length;richTextBox1.Focus();this.txt2_send.Rtf = "";txt2_send.Focus();}catch (System.Exception ex){MessageBox.Show(userName + ":" + ex.Message);}}//发送图片按钮private void btnImgFile_Click(object sender, EventArgs e){openfiledialog.Filter = "所有文件t(*.*)|*.*|位图文件t(*.bmp)|*.bmp|文件t (.jpg)|*.jpg|文件t(.gif)|*.gif";if (openfiledialog.ShowDialog() == DialogResult.OK){String strpath = openfiledialog.FileName;fstream = new FileStream(strpath, FileMode.Open);//此行和下一行是关键,得到文件字节数组BinaryReader breader = new BinaryReader(fstream);img = breader.ReadBytes((int)fstream.Length);//得到文件数组Clipboard.SetDataObject(Image.FromStream(fstream));txt2_send.Paste();imgflag = 1;}}//断开和服务器端连接óprivate void btn_close_Click(object sender, EventArgs e){socket.Close();thread.Abort();thread.Join(10);this.btn_req.Enabled = true;btn_close.Enabled = false;btnImgFile.Enabled = false;this.Text = " "+ userName + " "+ DateTime.Now.ToString() + " "+ DateTime.Now.DayOfWeek.ToString();this.richTextBox1.AppendText("System:" + userName + " 断开与服务器的连接!<-" + DateTime.Now.ToLongTimeString() + "->..... \r\n");}//退出聊天室private void btn_Exit_Click(object sender, EventArgs e){if (btn_close.Enabled != true){this.Close();Application.Exit();}else{MessageBox.Show("请先断开连接!");return;}}//取消发送private void btnRest_Click(object sender, EventArgs e) {txt2_send.Clear();}//清屏private void btnClear_Click(object sender, EventArgs e) {this.richTextBox1.Clear();}}}九.截图十.实验心得(注:可编辑下载,若有不当之处,请指正,谢谢!)。

网络课程设计实验报告--QQ聊天实现

网络课程设计实验报告--QQ聊天实现

计算机网络课程设计报告设计选题网络聊天室姓名马继鸣学号 0909090630完成时间 2012-1-12 一、需求分析聊天工具大多数由客户端程序和服务器程序外加服务器端,本程序采用客户机/服务器架构模式。

通过Java提供的Socket类来连接客户机和服务器并使客户机和服务器之间相互通信,由于聊天是多点对多点的而Java提供的多线程功能。

用多线程可完成多点对多点的聊天。

主要有两个应用程序,分别为服务器程序和客户端程序。

服务器应用程序主要用于消息转发,以及向所有用户发送系统消息等;客户端应用程序主要用于客户聊天记录的显示和信息输入。

采用Client/Server(C/S)体系结构,即客户机/服务器体系结构。

聊天服务器专门用于监控用户状态和转发消息,客户端负责接收消息的用户序列和消息文本发送到服务器。

该聊天系统实现群聊,用户登陆,退出聊天系统等功能。

二. 设计1.设计思想:课程设计中利用JAVA实现基于C/S模式的聊天程序。

聊天室共分为服务器端和客户端两部分,服务器端程序主要负责侦听客户发来的消息,客户端登录到服务器端才可以实现正常的聊天功能。

2.功能设计(1)服务器端的主要功能如下。

在特定端口上进行侦听,等待客户端连接。

用户可以配置服务端的侦听端口,默认端口为10000.当停止服务时,断开所有用户连接。

(2)客户端的主要功能如下。

连接到已经开启聊天服务的服务端。

当服务器端开启的话,用户可以随时登录与注销。

用户可以向所有人发送消息。

3.详细设计聊天室服务器端设计聊天室服务器中主要的功能文件的功能如下:MyButLis.java主要用于添加事件侦听和动作处理,具体是服务器按钮中的“终止”“发送”的处理。

public class MyButLis implements ActionListenerprivate MyServe server;private JTextField filed1;public void actionPerformed(ActionEvent e)MyChatSet.java服务器的线程队列,运行的方法,新增一个用户,则增加一个线程,并可以返回应答消息,给其余用户发送上下线信息,发送聊天信息(群聊私聊虽然已写,但是不知为何没有实现),发送用户列表。

简述网络聊天程序的原理

简述网络聊天程序的原理

简述网络聊天程序的原理
网络聊天程序的原理是基于网络通信技术,通过网络将用户之间的消息传递。

1. 客户端与服务器建立连接:客户端通过网络协议(如TCP/IP)与服务器建立连接,建立起双方之间的通信通道。

2. 用户登录或注册:用户使用客户端程序登录或注册,提供用户名和密码等信息,客户端将用户信息发送给服务器进行验证。

3. 接收和发送消息:用户通过客户端发送消息给服务器,服务器再将这些消息转发给其他在线的用户。

同时,服务器也会将其他用户发送的消息转发给当前用户。

4. 消息传递和存储:服务器会维护用户之间的关系和在线状态,并负责将消息传递给目标用户,并将消息进行存储。

5. 聊天记录存储:服务器通常会将聊天记录进行持久化存储,方便用户查询。

6. 退出聊天:当用户退出聊天时,客户端会发送请求告知服务器用户已经下线,服务器会更新用户的在线状态。

网络聊天程序的实现可以使用各种技术,如Socket编程、HTTP协议或
WebSockets等。

客户端可以是电脑上的软件应用,也可以是手机上的APP或浏览器中的网页。

服务器需要具备处理大量并发连接的能力,以及存储消息和用户信息的能力。

QQ通信原理

QQ通信原理
三、文件/自定义表情传送。
大家都知道,QQ可以传送文件,可以发送自定义表情。先说官方表情。官方表情实际发送的是命令字,而没有发送表情。客户端收到命令字后,会自动解释为对应的表情。因此,QQ2008正式版的客户端发出的新版表情,在2007beta4及以前的版本无法找到相对应的表情,就无法解释,看到的就会是空白信息,但查聊天记录就会有[表情]字样。
QQ有两种登陆模式
一种是比较不常用的:直接登陆服务器,所有信息由服务器转发,这种登陆模式有个特点就是你会发现你使用获取IP版本的QQ无法获取对方的IP~ (这个我不清楚有没有,但是肯定可以)
另一种是普通的:首先连接登陆服务器,在给对发发消息的时候,首先尝试与对方进行打洞连接,如果可以打通消息直接发送给对方,如果不能打通,则消息转发服务器,由服务器转发.(传文件会优先P2P,不行再选择中转,不知道聊天是不是优先P2P的,还是聊天文字是中转的?图片呢?会员表情?这个的确要问tx了,技术上的都是可以实现,选择什么只能问tx了)
二、聊天消息通信。
采用UDP协议,通过服务器中转方式。因此,现在的IP侦探在你仅仅跟对方发送聊天消息的时候是无法获取到IP的。大家都知道,UDP 协议是不可靠协议,它只管发送,不管对方是否收到的,但它的传输很高效。但是,作为聊天软件,怎么可以采用这样的不可靠方式来传输消息呢?于是,腾讯采用了上层协议来保证可靠传输:如果客户端使用UDP协议发出消息后,服务器收到该包,需要使用UDP协议发回一个应答包。如此来保证消息可以无遗漏传输。之所以会发生在客户端明明看到“消息发送失败”但对方又收到了这个消息的情况,就是因为客户端发出的消息服务器已经收到并转发成功,但客户端由于网络原因没有收到服务器的应答包引起的。
自定义表情的传送是以文件传输方式进行的。

QQ 聊天程序的网络通信原理

QQ 聊天程序的网络通信原理

QQ 聊天程序的网络通信原理卢平(通信工程(2)班 E09680220)QQ的通信协议QQ的通信协议是一套基于二进制数据的自己开发的应用层网络协议。

其中使用一些公司的加密算法。

QQ基本通信协议支持udp和tcp两种基本协议方式。

两种方式的基本数据结构是一样的。

只是tcp包多了一个描述长度的头部。

QQ的通信原理QQ 聊天程序采用的是C/S 通信模式,即客户/服务模式,它把一个应用划分成功能不同的两个部分,分别在不同的计算机上运行,其中一个为服务端程序,用来响应和提供固定的服务,一个为客户端程序,用来向服务端提出请求和要求某种服务。

在数量关系上,通常有一对一的(即一个服务端程序和一个客户端程序之间通信),也有一对多的(即一个服务端程序和多个客户端程序之间通信),也有多对多的(即多个服务端程序和多个客户端程序之间通信)。

所谓服务端程序、客户端程序也是相对的概念,有时在一个程序中既有服务端又有客户端的功能。

QQ 聊天程序分成了两个程序,一个安装在腾讯公司的服务器上,我们称之为服务端程序,一个安装在QQ 用户的计算机上,我们称之为客户端程序。

在许多介绍网络通信编程的书籍中有关网络聊天的例子,当一个客户要与另一个客户聊天时,第一个客户先把聊天数据发送给服务器,然后服务器再把聊天数据转发给第二个客户,服务器好像一个中转站,这在客户数量比较少时,服务器还能承受,在客户数量比较多时,服务器肯定要瘫痪。

何况客户之间还要传送文件、语音聊天、视频聊天等等,为了减少服务器的压力,各客户端之间需要直接通信。

1。

在服务端和客户端之间(一对多)用于客户端程序登录,验证用户密码,获取其它在线好友信息等等。

2。

在客户端和客户端之间(多对多)用于在线好友间直接通信聊天。

此时每个客户端程序上既有实现服务端功能的部分,又有实现客户端功能的部分,前者用于接收聊天数据,后者用于发送聊天数据。

在用C/S 模式进行通信时,作为客户端在请求与服务端连接时需要知道服务端的IP 地址,腾讯公司的服务器具有固定的公网地址,这没有问题。

JAVA编写QQ聊天系统指导书

JAVA编写QQ聊天系统指导书

JAVA编写QQ聊天系统指导书一、QQ聊天系统简介1、模拟聊天系统包含两个方面,服务器端和客户端。

2、服务器端任务:建立一个ServerSocket,与客户端建立通信通道,不断侦听是否有客户端连接或者断开连接。

服务器端是一个信息转发中心,所有客户端的信息都传到服务器端,由服务器端根据要求分发信息。

3、客户端任务:建立一个Socket,与服务器端建立通信通道,向服务器端发送信息,并接收来自服务器的信息。

二、QQ聊天系统测试1、教师机新建一个java project,命名为QQchat,将“QQ聊天系统素材”下服务器端解压,将解压后的两个包com,client复制到QQchat/src下,运行Server.java。

弹出如图1-1所示图形界面,点击“开始”,将弹出如图1-2所示图形界面,服务器即打开。

图1-1 图1-22、指导学生新建一个java project,命名为QQchat,在“QQ聊天系统素材”下载客户端,将客户端下载解压,将解压后的两个包com,client复制到QQchat/src下,运行Client.java,将弹出如图1-3所示图形界面,输入服务器的ip,port,以及帐户名(自已姓名)登录,将弹出如图1-4所示图形界面。

点击如图1-5所示图形界面的下拉列表,在发送框中输入信息发送,就可以进行群聊或私聊。

图1-3 图1-4 图1-54、指导同学们下载服务器端,同学们轮流运行服务器程序,其它同学通过某个同学的服务器程序进行聊天。

不同的服务器以IP地址区别。

需要提醒学生注意的是:只有登录同一个服务器的客户端才能相互聊天,测试时服务器端只能有一个,学生们需要轮流做服务器,而客户端可以有多个,没有限制。

三、QQ聊天系统设计与实现操作步骤。

任务一目的:通过网络编程,让同学们与老师互通字节信息。

老师做服务器,学生做客户端。

具体操作步骤:教师与学生都新建一个java project,命名如zhangsanQQchat(以本人姓名+QQchat为文件名),在src下新建一个other包,教师在other包下新建Server.java 类并运行。

QQ聊天程序的网络通信原理及编程

QQ聊天程序的网络通信原理及编程
Public Const '表示本数据中包含在线好友的 IP 地址和 ID Public Const Login = "User Login" '表示本数据中包含登录用户的用户 ID 和密码 Public Const NotUser = "IsNot User" '本数据含义为“不是合法用户” Public Const IsUser = "ThisIsUser" '本数据含义为“是合法用户” 为了识别数据含义方便,含义标记字符串长度一致,我这里采用的长度为 10。 Public Const HeadLength = 10 关于分割标记符和结束标记符,我采用数值 1 和 2 转字符的方法,因为它们转成的字符不是 普通字符,不会和传送的数据如用户 ID、密码、IP 地址等字符串数据混淆。 具体发送数据通过 SendData 方法进行,发送登录用户名和密码的语句如下,数据的格式为: 数据含义标记字符串+用户名+分割标记符+密码+结束标记符。 Private Sub WinsockClient_Connect() WinsockClient.SendData Login & TextUsername.Text & Chr(1) & TextPassword.Text & Chr(2) End Sub (5)接收收据 当有数据到达时,程序会收到消息触发 DataArrival 事件,所以不论服务端还是客户端程序 接收数据的工作在 DataArrival 事件方法中完成。具体接收数据使用 GetData 方法进行,为
本程序中用到的 Winsock 控件如下表:
控件名 是否为数组
作用 在哪个程序中

QQ工作原理--开发IM即时通讯工具

QQ工作原理--开发IM即时通讯工具

QQ工作原理--开发IM即时通讯工具IM即时通讯工具在现代社会已经成为我们日常交流的重要工具之一。

其中,QQ作为中国最著名的即时通讯软件之一,拥有大量的用户群体。

本文将从服务器架构、消息传输、数据加密等方面介绍QQ的工作原理。

一、服务器架构QQ的服务器架构是其高效运行的基础。

QQ采用了分布式服务器架构,即将服务划分为多个模块,并将这些模块部署在不同的服务器上。

这样一来,不同服务器之间可以并行处理用户请求,提高了系统的并发能力和处理速度。

1. 登录服务器登录服务器是QQ的核心模块之一,负责处理用户的登录请求。

当用户启动QQ客户端并输入正确的账号密码后,登录服务器会进行身份验证,验证通过后,将用户所在的服务器信息返回给客户端。

这样,用户就可以和其他在线用户建立连接并进行即时通讯。

2. 聊天服务器聊天服务器负责处理用户间的消息传输。

当用户发送消息时,消息将首先发送到聊天服务器,服务器再将消息转发给目标用户。

这种方式可以实现即时消息的实时传输,并且保证消息的可靠性。

3. 存储服务器存储服务器用于存储用户的个人资料、聊天记录等数据。

用户的个人资料包括账号信息、好友列表等,而聊天记录则包括用户之间的聊天内容、发送时间等信息。

存储服务器的设计可以保证用户数据的安全性和可靠性。

二、消息传输QQ使用了TCP/IP协议进行消息传输。

TCP协议可保障消息的可靠传输,保证消息不会丢失或损坏。

而IP协议则负责寻址和路由,确保消息能够准确地发送到目标用户。

在消息传输的过程中,QQ采用了类似于邮局的方式。

发送消息的用户相当于写信人,聊天服务器相当于邮局,接收消息的用户相当于收信人。

发送消息时,源用户将消息发送给聊天服务器,服务器再将消息转发给目标用户。

这样的设计可以确保消息能够准确地传递到目标用户手中。

三、数据加密为了保障用户的隐私和信息安全,QQ采用了数据加密技术。

在用户登录时,QQ客户端会将用户的密码进行加密处理后再发送给服务器。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Exit For
End If
Next i End If End Sub
(4)发送登录的用户名和密码 客户端程序在服务端程序接受连接后会收到消息触发 Connect 事件,对客户端而言在 Connect 事件方法中发送登录用户名和密码是最佳时机,为了使接收数据的一方明白收到的数据代表 什么含义,每条数据最前面有代表不同含义的数据含义标记字符串,每条数据后有相同的数 据结束标记符,每条数据中各子数据间有子数据分割标记符。各数据含义步骤如下:
(1)监听
先在窗体上加一个 Winsock 控件,名称设为“WinsockServer”。由于服务端需要和所有客 户端通信,需要很多 Winsock 控件,因此把刚加入的 Winsock 控件 WinsockServer 改为数组, 只要将 Winsock 控件的 Index 属性设为 0 即可,此时 WinsockServer 数组只有一个元素,以 后可根据需要动态增减。当窗体载入时,只会创建 WinsockServer(0)这一个 Winsock 控件 实例。作为服务端程序,首先要有一个 Winsock 用于监听客户端的连接请求,自然就 用 WinsockServer(0)作为监听 Winsock,所以先要设置其通信协议为 TCP,然后设置本地端口, 以便客户端通过该端口与服务端连接,最后通过 Listen 方法监听。
1.在服务端和客户端之间(一对多)
用于客户端程序登录,验证用户密码,获取其它在线好友信息等等。
2.在客户端和客户端之间(多对多)
用于在线好友间直接通信聊天。此时每个客户端程序上既有实现服务端功能的部分,又有实 现客户端功能的部分,前者用于接收聊天数据,后者用于发送聊天数据。
在用 C/S 模式进行通信时,作为客户端在请求与服务端连接时需要知道服务端的 IP 地址, 腾讯公司的服务器具有固定的公网地址,这没有问题。但是在客户端和客户端之间通信时, 每个用户的 IP 地址都是 ISP 所给的临时地址,无法固定,那么某个用户要与另一个用户连 接时,怎么知道对方的 IP 地址呢?当一个用户连接到 Internet 后,获得了一个临时的公网 地址,当登录到 QQ 时,QQ 服务端会获得该上线用户的 IP 地址,然后告知其他要与该上线 用户聊天的用户,其他用户就可以连接该用户与之直接通信了。
Type OnlineUserInformation
bUsed As Boolean ‘对应下标的 Winsock 控件是否已被载入在用
UserID As String ‘对应的用户 ID
IPAddr As String ‘对应的客户机 IP 地址
bLogined As Boolean ‘对应的用户是否登录
Public Const '表示本数据中包含在线好友的 IP 地址和 ID Public Const Login = "User Login" '表示本数据中包含登录用户的用户 ID 和密码 Public Const NotUser = "IsNot User" '本数据含义为“不是合法用户” Public Const IsUser = "ThisIsUser" '本数据含义为“是合法用户” 为了识别数据含义方便,含义标记字符串长度一致,我这里采用的长度为 10。 Public Const HeadLength = 10 关于分割标记符和结束标记符,我采用数值 1 和 2 转字符的方法,因为它们转成的字符不是 普通字符,不会和传送的数据如用户 ID、密码、IP 地址等字符串数据混淆。 具体发送数据通过 SendData 方法进行,发送登录用户名和密码的语句如下,数据的格式为: 数据含义标记字符串+用户名+分割标记符+密码+结束标记符。 Private Sub WinsockClient_Connect() WinsockClient.SendData Login & TextUsername.Text & Chr(1) & TextPassword.Text & Chr(2) End Sub (5)接收收据 当有数据到达时,程序会收到消息触发 DataArrival 事件,所以不论服务端还是客户端程序 接收数据的工作在 DataArrival 事件方法中完成。具体接收数据使用 GetData 方法进行,为
二、编程
1.登录
使用 QQ 的人都知道,用 QQ 聊天第一步是登录,这一步看似简单,其实程序做了不少事情。 当用户启动 QQ 聊天客户端程序,出现登录界面,用户输入用户名和密码,点击登录按钮后, 在用户机上的客户端程序首先请求与服务端程序建立连接,服务端程序接受客户端程序连接 请求。客户端程序在确保已和服务端程序建立连接后发送登录时用户输入的用户名和密码, 服务端程序收到后,根据用户信息数据库中数据验证。如果验证为合法用户,客户端程序则 显示聊天窗体,并从服务端获取在线好友信息,以便直接与各在线好友逐一建立新的通信机
WinsockClient.Connect ‘请求与服务端程序建立连接
End Sub
(3)接受客户端程序连接请求
当客户端请求与服务端程序建立连接时,处于监听状态的服务端会收到消息触 发 ConnectionRequest 事 件 , 所 以 服 务 端 程 序 接 受 客 户 端 程 序 连 接 请 求 的 工 作 在 ConnectionRequest 事件方法中完成。由于 WinsockServer(0)专用于监听,所以要新加载一 个 Winsock 控 件 与 该 客 户 端 通 信 , 为 了 保 留 每 个 在 线 客 户 的 信 息 , 我 定 义 了 一 个 OnlineUserInformation 结构类型的数组 OnlineUserInfo,它和 Winsock 控件数组相对应, 比 如 OnlineUserInfo(i) 中 存 放 的 是 与 WinsockServer (i) 通 信 客 户 端 的 信 息 , 其 中 OnlineUserInfo(i).bUsed 表示 WinsockServer (i)控件是否已被载入在与某个客户端通信 使用,如未使用,则通过 Load 方法将 WinsockServer (i)控件动态载入,随后调用 Accept 方法接受客户端程序连接请求。其中 MaxOnlineUser 是一个常量,表示最大在线用户数量。
本程序中用到的 Winsock 控件如下表:
控件名 是否为数组
作用 在哪个程序中
WinsockServer 是 用于和客户端通信 服务端程序
WinsockClient 否 用于和服务端通信 客户端程序
WinsockClientServer 是 用于接收在线好友的聊天信息 客户端程序
WinsockClientClient 是 用于向在线好友发送聊天信息 客户端程序
了防止客户端发送来的数据太多,服务端来不及处理,我定义了一个字符串数组 BufferRecv, 该 数 组 与 WinsockServer 控 件 数 组 对 应 , WinsockServer(Index) 控 件 收 到 的 数 据 添 加 在 BufferRecv(Index)中,然后通过结束标记符在 BufferRecv(Index)中取出一条条数据进行分析。 如果是客户登录,则获取用户名和密码,然后通过自定义函数 Lookfor 在数据库中验证。如 果验证为合法用户,则发送“是合法用户”数据标记,然后将用户 ID 和用户机器的 IP 等信息 置于一个在线用户信息的结构数组中备用。然后通过自定义函数 GetFriend 在数据库中获取 该用户的所有好友 ID 及好友人数,并根据在线用户信息数组逐一判断各个好友是否在线, 如果在线,则将在线好友的 ID 及 IP 地址发送给刚登录的客户,同时也将刚登录客户的 ID 及 IP 地址发送给在线好友,以便他们相互之间能够通信。如果验证为非法用户,则发送“不 是合法用户”数据标记,并将与该客户通信用的 Winsock 控件卸载。
QQ 聊天程序的网络通信原理及编程
、 QQ 聊天程序采用的是 C/S 通信模式,即客户/服务模式,它把一个应用划分成功能不同的两 个部分,分别在不同的计算机上运行,其中一个为服务端程序,用来响应和提供固定的服务, 一个为客户端程序,用来向服务端提出请求和要求某种服务。在数量关系上,通常有一对一 的(即一个服务端程序和一个客户端程序之间通信),也有一对多的(即一个服务端程序和 多个客户端程序之间通信),也有多对多的(即多个服务端程序和多个客户端程序之间通信)。 所谓服务端程序、客户端程序也是相对的概念,有时在一个程序中既有服务端又有客户端的 功能。QQ 聊天程序分成了两个程序,一个安装在腾讯公司的服务器上,我们称之为服务端 程序,一个安装在 QQ 用户的计算机上,我们称之为客户端程序。在许多介绍网络通信编程 的书籍中有关网络聊天的例子,当一个客户要与另一个客户聊天时,第一个客户先把聊天数 据发送给服务器,然后服务器再把聊天数据转发给第二个客户,服务器好像一个中转站,这 在客户数量比较少时,服务器还能承受,在客户数量比较多时,服务器肯定要瘫痪。何况客 户之间还要传送文件、语音聊天、视频聊天等等,为了减少服务器的压力,各客户端之间需 要直接通信。
If Index = 0 Then
For i = 1 To MaxOnlineUser
If Not OnlineUserInfo(i).bUsed Then
Load WinsockServer(i)
WinsockServer(i).Accept requestID
OnlineUserInfo(i).bUsed = True
End Type
Public OnlineUserInfo(1 To MaxOnlineUser) As OnlineUserInformation
Private Sub WinsockServer_ConnectionRequest(Index As Integer, ByVal requestID As Long)
相关文档
最新文档