利用TCP协议通过Socket编写的网络聊天工具1-客户端

面向对象课程大作业要求写一个面向对象设计的工程,所以我选择了网络聊天。

整个项目源码下载地址:http://download.csdn.net/detail/weixingstudio/4301232

具体的分析以后给出,先给出部分代码实现。

这里的实现只有客户端,服务器端下一节给出。

登录窗口的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using UtilityClass;
using System.Net;
using System.Net.Sockets;
using System.Collections.Specialized;

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

        private void button_cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void button_OK_Click(object sender, EventArgs e)
        {
            VerifyUserInfo verify = new VerifyUserInfo();
            string userName = textBox1.Text.Trim();
            string serverIP = textBox2.Text.Trim();
            string serverPort = textBox3.Text.Trim();
            if (!verify.VerifyUserName(userName))
            {
                MessageBox.Show("请重新填写用户名!","提示");
                textBox1.Focus();
            }
            else
            {
               if (!verify.VerifyServerIP(serverIP))
               {
                   MessageBox.Show("请重新填写服务器IP!", "提示");
                   textBox2.Focus();
               }
               else
               {
                   if (!verify.VerifyServerPort(serverPort))
                   {
                       MessageBox.Show("请重新填写服务器端口!", "提示");
                       textBox3.Focus();
                   }
                   else
                   {
                       // 打开聊天窗口
                       //MessageBox.Show("Good", "提示");
                       try
                       {
                           int serverPort_int=int.Parse(serverPort);
                           ServerConfig serverConfig = new ServerConfig(serverIP, serverPort_int);
                           IPAddress serverIPAddress = IPAddress.Parse(serverConfig.ServerIP);
                           TcpClient client = new TcpClient();
                           client.Connect(serverIPAddress, serverConfig.ServerPort);
                           if (client==null)
                           {
                               MessageBox.Show("连接服务器失败,请重新填写服务器数据或者查看服务器运行状态!", "提示");
                               textBox1.Focus();
                           }
                           else
                           {
                               // 连接成功以后的操作
                               NetworkStream clientNetWorkStream = client.GetStream();
                               // 发送用户名
                               byte[] bytes2beSend=Command.EncodeCommand(userName);
                               clientNetWorkStream.Write(bytes2beSend, 0, bytes2beSend.Length);
                               byte[] receiveBuffer=new byte[serverConfig.MaxBuffer];
                               clientNetWorkStream.Read(receiveBuffer, 0, receiveBuffer.Length);
                               string connResult = Command.DecodeCommand(receiveBuffer);
                               if (connResult==Command.RedundantUserName)
                               {
                                   MessageBox.Show("重复的用户名,请重新填写用户名。", "提示");
                               }
                               else if (connResult==Command.ExceedMaxAllowedNumber)
                               {
                                   MessageBox.Show("超出了服务器最多允许的连接数量,请稍后连接!", "提示");
                               }
                               else if (connResult==Command.ConnectConfirm)
                               {
                                    请求用户列表
                                    开始先请求一个在线用户列表
                                   //byte[] cmd = new byte[serverConfig.MaxBuffer];
                                   //cmd = Command.EncodeCommand(Command.RequestOnlineUser);
                                   //clientNetWorkStream.Write(cmd, 0, cmd.Length);
                                    读取在线用户列表
                                   //clientNetWorkStream.Read(cmd, 0, cmd.Length);
                                   //StringCollection sc = Command.DeserializeOnlineUser(cmd);
                                   // 打开聊天窗口
                                   MainChatFrm mainChat = new MainChatFrm(userName,serverConfig,clientNetWorkStream); // 将数据流传递给另外一个窗口
                                   mainChat.Owner = this;
                                   this.Hide();
                                   mainChat.Show();
                               }
                           }
                       }
                       catch (System.Exception ex)
                       {
                           MessageBox.Show("出错了!远程服务器没有响应。连接服务器失败,请重新填写服务器数据或者查看服务器运行状态!", "提示");
                       }
                   }
               }
            }
        }
    }
}


主聊天窗口的代码:

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

namespace Client
{
    public partial class MainChatFrm : Form
    {
        Thread receiveMegThread;
        ServerConfig serverConfig;
        NetworkStream networkStream;
        string userName;
        private bool isDisconnected = false;

        private delegate void showMessage(string s);
        private delegate void addOnlineUser(string s);

        public MainChatFrm()
        {
            InitializeComponent();
        }

        public MainChatFrm(string name, ServerConfig config, NetworkStream ns)
        {
            InitializeComponent();
            this.listBox_onlineuser.Items.Clear();
            this.userName = name;
            this.serverConfig = config;
            this.networkStream = ns;
            this.label_username.Text += userName;
            this.label_serverIP.Text += serverConfig.ServerIP + ":" + serverConfig.ServerPort;
            this.richTextBox1.Text += "你好 " + userName + ",欢迎来到微星聊天室!   " + DateTime.Now + "\n";
         
            try
            {
                // 开启接收消息的线程
                receiveMegThread = new Thread(new ThreadStart(ReceiveMessage));
                receiveMegThread.IsBackground = true;
                receiveMegThread.Start();
                Thread.Sleep(100);
            }
            catch (System.Exception ex)
            {
            	//
            }
        }

        /// <summary>
        /// 接收消息处理线程函数
        /// </summary>
        private void ReceiveMessage()
        {
            try
            {
                while (true)
                {
                    byte[] receiveBuffer=new byte[serverConfig.MaxBuffer];
                    networkStream.Read(receiveBuffer, 0, receiveBuffer.Length);
                    string cmd_from_server = Command.DecodeCommand(receiveBuffer);
                    switch (cmd_from_server)
                    {
                            // 服务器通知有用户上线
                        case Command.SomeoneConnected:
                            {
                                // 获取用户名
                                byte[] cmd=new byte[serverConfig.MaxBuffer];
                                networkStream.Read(cmd, 0, cmd.Length);
                                string name = Command.DecodeCommand(cmd);
                                if (name!=userName)
                                {
                                    // 线程安全的添加数据到RichTextBox
                                    AddText2RTB("用户:" + name + " 上线了!" + "  " + DateTime.Now);
                                }
                                else
                                {
                                    // nothing
                                }
                                // 请求最新的用户列表
                                cmd = Command.EncodeCommand(Command.RequestOnlineUser);
                                //  发送请求在线用户列表命令
                                networkStream.Write(cmd, 0, cmd.Length);
                                break;
                            }

                            // 服务器发送用户列表
                        case Command.SendOnlinUserList:
                            {
                                // 接收数据
                                networkStream.Read(receiveBuffer, 0, receiveBuffer.Length);
                                StringCollection sc = Command.DeserializeOnlineUser(receiveBuffer);
                                ClearOnlineUserList();
                                ClearComboList();
                                foreach (string s in sc)
                                {
                                    // 线程安全的添加数据
                                    AddOnlineUserList(s);
                                }
                                break;
                            }

                            // 有人离开
                        case Command.SomeoneLeave:
                                {
                                    byte[] cmd=new byte[serverConfig.MaxBuffer];
                                    networkStream.Read(cmd, 0, cmd.Length);
                                    string name = Command.DecodeCommand(cmd);
                                    AddText2RTB("用户:" + name + " 离开了系统." + DateTime.Now);
                                    // 线程安全的移除下线的用户
                                    Action<object> call = delegate(object s) { this.listBox_onlineuser.Items.Remove(s); 
                                        this.comboBox_selectUser.Items.Remove(s); };
                                    this.listBox_onlineuser.Invoke(call, name);
                                    break;
                                }
                            // 有广播消息
                        case Command.BroadcastAll:
                                {
                                    // 获取广播消息的用户名
                                    byte[] cmd=new byte[serverConfig.MaxBuffer];
                                    networkStream.Read(cmd, 0, cmd.Length);
                                    string name = Command.DecodeCommand(cmd);
                                    AddText2RTB("用户:" + name + "在" + DateTime.Now + "对大家说:");
                                    byte[] msg=new byte[serverConfig.MaxBuffer];
                                    networkStream.Read(msg, 0, msg.Length);
                                    string message = Command.DecodeCommand(msg);
                                    AddText2RTB(message);
                                    break;
                                }
                            // 对这个用户单独发送数据
                        case Command.SendMessage2One:
                                {
                                    byte[] cmd = new byte[serverConfig.MaxBuffer];
                                    networkStream.Read(cmd, 0, cmd.Length);
                                    string name_from = Command.DecodeCommand(cmd);
                                    // 
                                    Thread.Sleep(20);
                                    networkStream.Read(cmd, 0, cmd.Length);
                                    string message = Command.DecodeCommand(cmd);
                                    AddText2RTB("用户:" + name_from + "在" + DateTime.Now + "对你悄悄的说:");
                                    AddText2RTB(message);
                                    break;
                                }

                            // 请求抖动
                        case Command.VibrateOne:
                                {
                                    byte[] cmd = new byte[serverConfig.MaxBuffer];
                                    networkStream.Read(cmd, 0, cmd.Length);
                                    string name_from = Command.DecodeCommand(cmd);
                                    AddText2RTB("用户:" + name_from + "在" + DateTime.Now + "给您发送了一个抖动");
                                    Vibrate();
                                    break;
                                }

                        case Command.VibrateAll:
                                {
                                    byte[] cmd = new byte[serverConfig.MaxBuffer];
                                    networkStream.Read(cmd, 0, cmd.Length);
                                    string name_from = Command.DecodeCommand(cmd);
                                    AddText2RTB("用户:" + name_from + "在" + DateTime.Now + "给所有人发送了一个抖动");
                                    Vibrate();
                                    break;
                                }

                        case Command.ServerShutdown:
                                {
                                    AddText2RTB("服务器已经关闭,请退出程序,重新连接服务器。");
                                    this.networkStream.Close();
                                    networkStream=null;
                                    this.button_send.Enabled = false;
                                    break;
                                }
                        default:
                            {
                                break;
                            }
                    }
                }
            }
            catch (System.Exception ex)
            {
            	// 服务器连接失败,清理连接
                if (networkStream!=null)
                {
                    MessageBox.Show("服务器连接失败!");
                    networkStream.Close();
                    networkStream = null;
                }
            }
        }

        private void ClearOnlineUserList()
        {
            Action call = delegate() { this.listBox_onlineuser.Items.Clear(); };
            this.listBox_onlineuser.Invoke(call);
        }

        private void ClearComboList()
        {
            Action call = delegate() { this.comboBox_selectUser.Items.Clear(); };
            this.comboBox_selectUser.Invoke(call);
        }

        private void AddOnlineUserList(string user)
        {
            addOnlineUser call = delegate(string s) { this.listBox_onlineuser.Items.Add(s);
                this.comboBox_selectUser.Items.Add(s); };
            this.listBox_onlineuser.Invoke(call,user);
        }

        //private void fromClosed(object sender, FormClosedEventArgs e)
        //{
        //    DisConnectWithServer();
        //    this.Owner.Close();
        //    this.Close();
        //}

        private void button_close_Click(object sender, EventArgs e)
        {
            if (networkStream != null)
            {
                DialogResult ret;
                ret = MessageBox.Show("确定与服务器断开连接吗?",
                                      "退出",
                                      MessageBoxButtons.OKCancel,
                                      MessageBoxIcon.Question,
                                      MessageBoxDefaultButton.Button2);

                if (ret == DialogResult.OK)
                {
                    try
                    {
                        isDisconnected = true;
                        // 向服务器发送离线请求
                        byte[] cmd = Command.EncodeCommand(Command.DisConnect);
                        networkStream.Write(cmd, 0, cmd.Length);
                        if (receiveMegThread != null)
                        {
                            receiveMegThread.Abort();
                        }
                        if (networkStream != null)
                        {
                            // 关闭网络流
                            networkStream.Close();
                            networkStream.Dispose();
                        }
                        this.Owner.Close();
                        this.Close();
                    }
                    catch (System.Exception ex)
                    {

                    }
                }
            }
            else
            {
                this.Owner.Close();
                this.Close();
            }
        }

        /// <summary>
        /// 与服务器断开连接
        /// </summary>
        private void DisConnectWithServer()
        {
           
        }

        [DllImport("user32.dll")]
        public static extern bool FlashWindow(IntPtr hWnd, bool bInvert);

        /// <summary>
        /// 给用户发送抖动
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox1_Click(object sender, EventArgs e)
        {
            if (radioButton_all.Checked)
            {
                //AddText2RTB("禁止对所有用户发送抖动!");
                // 发送命令
                byte[] cmd = Command.EncodeCommand(Command.VibrateAll);
                networkStream.Write(cmd, 0, cmd.Length);
                Thread.Sleep(20);
                AddText2RTB("您给所有人发送了一个抖动");
                Vibrate();
            }
            else if (radioButton_one.Checked)
            {
                // 给当个用户发送抖动
                if (this.comboBox_selectUser.SelectedItem==null)
                {
                    MessageBox.Show("请选择一个私聊用户");
                }
                else
                {
                    string name_private = comboBox_selectUser.SelectedItem.ToString();
                    if (name_private == userName)
                    {
                        MessageBox.Show("您不能给自己发送抖动!");
                    }
                    else
                    {
                        // 发送命令
                        byte[] cmd=Command.EncodeCommand(Command.VibrateOne);
                        networkStream.Write(cmd, 0, cmd.Length);
                        Thread.Sleep(20);
                        // 发送抖动用户
                        cmd = Command.EncodeCommand(name_private);
                        networkStream.Write(cmd, 0, cmd.Length);
                        Thread.Sleep(20);
                        Vibrate();
                    }
                }

            }
        }

        private void Vibrate()
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                FlashWindow(this.Handle, true);
            }
            Nudge();
        }

        /// <summary>
        /// 产生闪屏振动效果
        /// </summary>
        private void Nudge()
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.WindowState = FormWindowState.Normal;
            }
            int i = 0;
            Point _old = this.Location;
            Point _new1 = new Point(_old.X + 2, _old.Y + 2);
            Point _new2 = new Point(_old.X - 2, _old.Y - 2);
            //_sp2.Play();
            while (i < 4)
            {
                this.Location = _new1;
                Thread.Sleep(60);
                this.Location = _new2;
                Thread.Sleep(60);
                i++;
            }
            this.Location = _old;
        }

        private void chatFrm_close(object sender, FormClosedEventArgs e)
        {
            if (!isDisconnected)
            {
                try
                {
                    if (networkStream != null)
                    {
                        DialogResult ret;
                        ret = MessageBox.Show("确定与服务器断开连接吗?",
                                              "退出",
                                              MessageBoxButtons.OKCancel,
                                              MessageBoxIcon.Question,
                                              MessageBoxDefaultButton.Button2);

                        if (ret == DialogResult.OK)
                        {
                            isDisconnected = true;
                            // 向服务器发送离线请求
                            byte[] cmd = Command.EncodeCommand(Command.DisConnect);
                            networkStream.Write(cmd, 0, cmd.Length);
                            if (receiveMegThread != null)
                            {
                                receiveMegThread.Abort();
                            }
                            if (networkStream != null)
                            {
                                // 关闭网络流
                                networkStream.Close();
                                networkStream.Dispose();
                                networkStream = null;
                            }
                            this.Owner.Close();
                            this.Close();
                        }
                    }
                    else
                    {
                        isDisconnected = true;
                        this.Owner.Close();
                        this.Close();
                    }
                   
                }
                catch (System.Exception ex)
                {
                	//
                }
            } 
        }

        private void AddText2RTB(string msg)
        {
            if (this.richTextBox1.InvokeRequired)
            {
                showMessage call = delegate(string s) { this.richTextBox1.Text += s + "\n"; };
                this.richTextBox1.Invoke(call, msg);
            }
            else
            {
                this.richTextBox1.Text += msg + "\n";
            }
        }

        /// <summary>
        /// 发送用户消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_send_Click(object sender, EventArgs e)
        {
            string messsage = this.richTextBox2.Text;
            if (Command.VerifyMessage(messsage))
            {
                // 验证将要发送的消息正确
                
                if (radioButton_all.Checked)
                {
                    // 给所有人发送消息
                    // 给服务器发送命令
                    byte[] cmd = Command.EncodeCommand(Command.BroadcastAll);
                    networkStream.Write(cmd, 0, cmd.Length);
                    Thread.Sleep(50);
                    // 发送要传送的数据
                    cmd = Command.EncodeCommand(messsage);
                    networkStream.Write(cmd, 0, cmd.Length);
                    AddText2RTB("你"  + "在 " + DateTime.Now + " 对大家说:");
                    AddText2RTB(messsage);
                    this.richTextBox2.Text = "";
                    this.richTextBox2.Focus();
                }
                else if (radioButton_one.Checked)
                {
                    // 给单个人发送消息
                    try
                    {
                        if (comboBox_selectUser.SelectedItem==null)
                        {
                            MessageBox.Show("请选择一个私聊用户");
                        }
                        string name_private = comboBox_selectUser.SelectedItem.ToString();
                        if (name_private == userName)
                        {
                            MessageBox.Show("您不能和自己私聊!");
                            this.richTextBox2.Text = "";
                            this.richTextBox2.Focus();

                        }
                        else
                        {
                            // 发送命令
                            byte[] cmd = Command.EncodeCommand(Command.SendMessage2One);
                            networkStream.Write(cmd, 0, cmd.Length);
                            Thread.Sleep(50);
                            //  发送对象名
                            cmd = Command.EncodeCommand(name_private);
                            networkStream.Write(cmd, 0, cmd.Length);
                            Thread.Sleep(50);
                            // 发送数据
                            cmd = Command.EncodeCommand(messsage);
                            networkStream.Write(cmd, 0, cmd.Length);
                            AddText2RTB("你" + "在 " + DateTime.Now + " 对 " + name_private + "说:");
                            AddText2RTB(messsage);
                            this.richTextBox2.Text = "";
                            this.richTextBox2.Focus();
                        }
                    }
                    catch (System.Exception ex)
                    {
                    	//
                    }
                   
                }
            }
            else
            {
                this.richTextBox2.Text = "";
                this.richTextBox2.Focus();
                AddText2RTB("请输入正确的消息然后在发送!!!" + DateTime.Now);
            }
        }

        /// <summary>
        /// 清除数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_clear_Click(object sender, EventArgs e)
        {
            this.richTextBox2.Text = "";
            this.richTextBox2.Focus();
        }

        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            this.richTextBox1.SelectionStart = this.richTextBox1.TextLength;
            this.richTextBox1.ScrollToCaret();
            if (this.WindowState == FormWindowState.Minimized)
            {
                FlashWindow(this.Handle, true);
            }
        }
    }
}


其中封装了两个在服务器端和客户端工程中都需要使用的配置类和命令类,下一节给出。

里面包含聊天室的客户端和服务器端的源文件和一份完整的设计报告。 一、 系统概要 本系统能实现基于VC++的网络聊天室系统。有单独的客户端、服务器端。 服务器应用程序能够接受来自客户端的广播,然后向客户端发送本机的IP与服务端口,让客户端接入到服务器进行聊天,检测用户名是否合法(重复),服务器责接收来自客户端聊天信息,并根据用户的需求发送给指定的人或所有人,能够给出上线下线提示。客户端能够发出连接请求,能编辑发送信息,可以指定发给单人或所有人,能显示聊天人数,上线下线用户等。 二、 通信规范的制定 服务请求规范: 服务器端: (1) 创建一个UDP的套接字,接受来自客户端的广播请求,当请求报文内容为“REQUEST FOR IP ADDRESS AND SERVERPORT”时,接受请求,给客户端发送本服务器TCP聊天室的端口号。 (2) 创建一个主要的TCP协议的套接字负责客户端TCP连接 ,处理它的连接请求事件。 (3)在主要的TCP连接协议的套接字里面再创建TCP套接字保存到动态数组里,在主要的套接字接受请求后 ,就用这些套接字和客户端发送和接受数据。 客户端: (1) 当用户按“连接”按钮时,创建UDP协议套接字,给本地计算机发广播,广播内容为“REQUEST FOR IP ADDRESS AND SERVERPORT”。 (2)当收到服务器端的回应,收到服务器发来的端口号后,关闭UDP连接。根据服务器的IP地址和端口号重新创建TCP连接。 故我思考:客户端一定要知道服务器的一个端口,我假设它知道服务器UDP服务的端口,通过发广播给服务器的UDP服务套接字,然后等待该套接字发回服务器TCP聊天室服务的端口号,IP地址用ReceiveForom也苛刻得到。 通信规范 通信规范的制定主要跟老师给出的差不多,并做了一小点增加: (增加验证用户名是否与聊天室已有用户重复,在服务器给客户端消息中,增加标志0) ① TCP/IP数据通信 --- “聊天消息传输格式 客户机 - 服务器 (1)传输“用户名” STX+1+用户名+ETX (2) 悄悄话 STX+2+用户名+”,”+内容+ETX (3) 对所有人说 STX+3+内容+ETX 服务器- 客户机 (0)请求用户名与在线用户名重复 //改进 STX+0+用户名+EXT (1)首次传输在线用户名 STX+1+用户名+ETX (2)传输新到用户名 STX+2+用户名+ETX (3)传输离线用户名 STX+3+用户名+ETX (4)传输聊天数据 STX+4+内容+ETX (注:STX为CHR(2),ETX 为CHR(3)) 三、 主要模块的设计分析 四、 系统运行效果 (要求有屏幕截图) 五、 心得与体会
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值