用Socket实现聊天小程序

最近在学习网络编程,发现也并没有想象中的那么难。以前总是有意无意听身边朋友在谈论多线程、Socket网络编程等等,由于对网络编程一无所知,所以给我一种“应该很难”的错觉。

       一台计算机和另一台计算机是如何通过网络互相通信、传递数据的?

  HTTP协议、TCP/IP、UDP到底是什么玩意?

    进程和线程有什么区别?

      IP地址、端口又是什么?

      大名鼎鼎的Socket是用来干嘛的?

 

       这些问题都是以前最困扰我的,这两天终于给弄称敨了。在这里简单巩固下,如果你也想知道这些问题的答案,就去看有关网络编程的书吧,真的很简单的。

  1.首先,什么是IP地址和端口??

  连入了一个网络(可以是互联网也可以是局域网)上的每一台计算机,都会被自动(或手动)分配一个IP地址,和手机有唯一的手机号码一样,IP地址也是用来标识每一台计算机身份的,一台计算机要想与另一台计算机通信,就必须要知道它的IP地址。

       连入了互联网上的计算机,IP地址是随机分配的。

       通过IP地址找到计算机就可以通信了吗?当然不能。

    我们知道,聊QQ,玩游戏,上网都是安装在计算机上的一个个软件。我们找到了计算机,但是数据到底是从哪一个应用程序(软件)发出来的呢,无法确定——端口,就是用来标识在计算机上运行的一个个应用程序的。端口号可以是0到65535之间的任一数字。一般10000以内的端口号已经被系统中的重要程序给占用了。比如通过浏览器发出的数据的端口号默认是80。

      有了IP和端口号,就可以与计算机上的应用程序进行数据传输了。

      2.什么是HTTP协议、TCP/IP和UDP?

      HTTP协议是超文本传输协议的总称,是在浏览器上访问页面使用最广泛的一种协议,它是无状态的,即它只负责发送请求和响应,执行完了就完了,不记录任何数据和信息。简单说,协议是为了方便在互联网上互相通信、共享资源、传递数据,大家约定好了的,都必须遵守的一种规范和标准。

     每一台计算机本身是相互独立的,在计算机或主机上都有一个网卡或路由器,IP地址就是给网卡或路由器分配的,TCP/IP和UDP也是协议,它们是实现计算机与计算机相互通信的协议。

     3.进程和线程

    计算机上每一个正在运行的应用程序就是一个进程,它是用来方便操作系统管理应用程序的。

       线程是操作系统为了管理数据的计算和执行而分配的一段时间片,大约是20毫秒。     

  每一个进程可以有一个或多个线程,在每一个C#程序中,默认有一个主线程,它会执行main()方法里面的代码,从上而下一行一行执行。

       当需要同时执行某段代码,即在执行某段代码的同时又要执行另外一段代码,就要另外开辟一个线程,即用到多线程。

比如聊天系统,一个人可以同时与多人进行聊天,他就需要接收来自多台计算机发送过来的消息,如果不用单线程的话,就只能接收到首先发送过来的那台计算机的数据,而其他计算机发送过来的数据就无法读取。

       最后,让我们来认识声名显赫的Socket。

       Socket其实也很简单,它就是.NET框架下的一个类,叫做套接字类。上面我们说了那么多,接收数据和发送数据到底是谁来做的——就是我们的Socket,通过它,我们就可以实现计算机与计算机进行数据传输了。

       Socket实现数据传输的几个关键方法:Listen()、 Bind()、 Connect()、 Accept()、Send()、Receive() 

    

      想做网络编程方面的开发,这些都是必须要知道的最基础知识。

      通过这几天的看书,正如吕老师所说,技术真的没有什么了不起的,不要望而生畏,都十分简单,但是什么才是最重要的,我目前不得而知。相信,随着不断的学习和进步,我会知道的。

      下面是我用Socket做的一个聊天小程序。大家会发现,也很简单。


图片

参考代码:

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 System.Net;
using System.Net.Sockets;

using System.Threading;
using System.Diagnostics;

namespace Socket_Chat
{
    public partial class Form1 : Form
    {
        private byte[] receiveMsgBtyes = new byte[1024];
        private static StringBuilder receiveMessage = new StringBuilder();
        private IPHostEntry hostEntry;
        private int localPort;

        //接收消息的套接字
        private Socket socketReceiver;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //程序加载即创建Socket(套接字)对象的实例
            this.socketReceiver = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //为本地进程随机生成一个端口号
            this.localPort = (new Random()).Next(10000,20000);
            this.txtLocalPort.Text = localPort.ToString();

            //获取本地主机IP对象实例
            this.hostEntry = Dns.GetHostByName(Dns.GetHostName());
            //IPHostEntry hostEntr = Dns.GetHostEntry(Dns.GetHostName());
            //IPHostEntry hostEntr = Dns.GetHostEntry(Dns.GetHostName());

            string hostIp = hostEntry.AddressList[0].ToString();
            this.txtLocalIp.Text = hostIp;


            //IPAddress hostIpAddress = IPAddress.Parse(hostIp);
            IPAddress hostIpAddress = hostEntry.AddressList[0];
            //IPAddress a = Dns.GetHostAddresses(Dns.GetHostName())[0];
           
            //获取本地主机进程端口实例
            IPEndPoint hostPort = new IPEndPoint(hostIpAddress, this.localPort);
            //IPEndPoint hostPort = new IPEndPoint(hostEntry.AddressList[0].Address, localPort);

            //绑定本地主机进程端口
            this.socketReceiver.Bind(hostPort);

            //开始监听
            this.socketReceiver.Listen(10);

            //启动进程接收消息(因为要接收多方发送过来的消息)
            Thread threadReceive = new Thread(new ThreadStart(this.ReceiveMessage));
            threadReceive.IsBackground = true;
            threadReceive.Start();

        }

        //接收消息
        private void ReceiveMessage()
        {
            //开始循环接受对方发出连接请求,一旦连接成功即返回一个套接字对象,该套接字包含对方IP和端口号
            //连接成功前此线程处于阻塞状态
            while (true)
            {
                try
                {
                    Socket clientSocket = this.socketReceiver.Accept();

                    //接收一串字节数组型的数据存入缓存
                    int receiveMsgLength = clientSocket.Receive(this.receiveMsgBtyes);
                    //将字节数组转换成字符串
                    string strMessage = Encoding.Default.GetString(this.receiveMsgBtyes, 0, receiveMsgLength);

                    Form1.receiveMessage.AppendLine(string.Format("来自{0}:{1}的消息 {2}:", this.hostEntry.AddressList[0].ToString(),

                      this.txtFriendPort.Text, DateTime.Now.ToString()));
                    Form1.receiveMessage.AppendLine("/r/n" + strMessage + "/r/n");
                   

                    this.txtMessageRecord.Text = Form1.receiveMessage.ToString();
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.Message,"错误提示");
                    this.socketReceiver.Shutdown(SocketShutdown.Both);
                    this.socketReceiver.Close();
                    break;
                }
            }

        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            if (this.txtFriendIp.Text == "")
            {
                MessageBox.Show("请输入对方IP!", "提示");
                return;
            }
            if (this.txtFriendPort.Text == "")
            {
                MessageBox.Show("请输入对方端口号!", "提示");
                return;
            }
            if (this.txtSendMessage.Text == "")
            {
                MessageBox.Show("消息不能为空!", "提示");
                return;
            }
            //发送消息的套接字
            Socket socketSender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //获取对方主机IP对象实例
            IPAddress friendIP = IPAddress.Parse(this.txtFriendIp.Text);
            //获取对方主机进程端口实例
            IPEndPoint friendPort = new IPEndPoint(friendIP, int.Parse(this.txtFriendPort.Text));

            //开启连接
            socketSender.Connect(friendPort);

            Form1.receiveMessage.AppendLine(string.Format("{0}:{1} {2}:", this.hostEntry.AddressList[0].ToString(),

                     this.localPort.ToString(), DateTime.Now.ToString()));
            Form1.receiveMessage.AppendLine("/r/n" + this.txtSendMessage.Text + "/r/n");

            //发送消息
            socketSender.Send(Encoding.Default.GetBytes(this.txtSendMessage.Text));
            this.txtMessageRecord.Text = Form1.receiveMessage.ToString();
            this.txtSendMessage.Text = "";
        }


        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                //this.SendMessageByKey += btnSend_Click;
                this.btnSend.Click += new System.EventHandler(this.btnSend_Click);
            }
        }

    }
}

   

        

 

 

                                                                                                                                                                点击我试试
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值