原文:http://www.cnblogs.com/technology/archive/2010/08/15/1799858.html

  程序设计成为简单的服务端和客户端之间的通信, 但通过一些方法可以将这两者进行统一起来, 让服务端也成为客户端, 让客户端也成为服务端, 使它们之间可以互相随时不间断的通信. 考虑到实现最原始的服务端和客户端之间的通信所需要的步骤对于写这样的程序是很有帮助的.

作为服务端, 要声明一个Socket A并绑定(Bind)某一个IP+这个IP指定的通信端口, 比如这个是127.0.0.1:9050, 然后开始监听(Listen), Listen可以监听来自多个IP传过来的连接请求, 具体可以同时连接几个客户端, Listen方法中可以设定一个参数. 如果Listen到某一个客户端发来连接请求了, 这时定义一个新的Socket B专门负责与这个客户端的通信, Socket B = A.Accept(). 这时可以获取这个客户端的IP和端口,  IPEndPoint C = (IPEndPoint)B.RemoteEndPoint, C.Address和C.Port分别表示客户端C的IP地址和端口. 这时通过B.Send()方法就可以给C发送消息了, B.Receive()可以接收客户端C发来的信息.

作为客户端, 也需要声明一个Socket D并绑定某一个IP+本机一个未被占用的端口, 定义IPEndPoint E表示要进行连接的服务端Socket, 要指明E的IP和端口, 这样才可以进行端口对端口之间的通信, 接下来就可以尝试D.Connect(E), 连接成功之后就可以发送和接收数据了, D.Send(), D.Receive.

发送消息时, 数据都是以字节或字节数组为单位进行传输的, 比如我客户端D要发送"Hello World"则要这样写: D.Send(Encoding.ASCII.GetBytes("Hello World")).  接受消息时, 也是以字节或字节数组, 比如服务端要接受D刚才发送的Hello World, 可以这样写: Byte[] data = new Byte[1024]; int receivedDataLength = B.Receive(data); string stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength); stringdata这时就是Hello World.

上面只是大概的阐述了服务端与客户端之间的通信过程, 在网上找到了具体的代码例子, 也贴过来参考参考. 这个例子没有将服务端与客户端统一起来, 他是分别写服务端和客户端的.

服务端代码

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using  System;
using  System;
using  System.Net;
using  System.Net.Sockets;
using  System.Text;
namespace  tcpserver
{
     ///   <summary>
     ///  Class1 的摘要说明。
     ///   </summary>
     class  server
    {
         ///   <summary>
         ///  应用程序的主入口点。
         ///   </summary>
        [STAThread]
         static   void  Main( string [] args)
        {
             //
             //  TODO: 在此处添加代码以启动应用程序
             //
            int  recv; // 用于表示客户端发送的信息长度
            byte [] data;// = new   byte [ 1024 ]; // 用于缓存客户端所发送的信息,通过socket传递的信息必须为字节数组
            IPEndPoint ipep = new  IPEndPoint(IPAddress.Any, 9050 ); // 本机预使用的IP和端口
            Socket newsock = new  Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            newsock.Bind(ipep); // 绑定
            newsock.Listen( 10 ); // 监听
            Console.WriteLine( " waiting for a client  " );
            Socket client = newsock.Accept(); //当有可用的客户端连接尝试时执行,并返回一个新的socket,用于与客户端之间的通信
            IPEndPoint clientip = (IPEndPoint)client.RemoteEndPoint;
            Console.WriteLine( " connect with client: " + clientip.Address + "  at port: " + clientip.Port);
            string  welcome = " welcome here! " ;
            data = Encoding.ASCII.GetBytes(welcome);
            client.Send(data,data.Length,SocketFlags.None); // 发送信息
            while ( true )
            { // 用死循环来不断的从客户端获取信息
                data = new   byte [ 1024 ];
                recv = client.Receive(data);
                Console.WriteLine( " recv= " + recv);
                if  (recv == 0 ) // 当信息长度为0,说明客户端连接断开
                     break ;
                Console.WriteLine(Encoding.ASCII.GetString(data, 0 ,recv));
                client.Send(data,recv,SocketFlags.None);
            }
            Console.WriteLine( " Disconnected from " + clientip.Address);
            client.Close();
            newsock.Close();
        }
    }
}

客户端代码

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace tcpclient
{
    ///   <summary>
    ///  Class1 的摘要说明。
    ///   </summary>
    class client
    {
        ///   <summary>
        ///  应用程序的主入口点。
        ///   </summary>
        [STAThread]
        static void Main(string[] args)
        {
            //
            //  TODO: 在此处添加代码以启动应用程序
            //
            byte[] data = new byte[1024];
            Socket newclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            newclient.Bind(new IPEndPoint(IPAddress.Any, 905));
            Console.Write(" please input the server ip: ");
            string ipadd = Console.ReadLine();
            Console.WriteLine();
            Console.Write(" please input the server port: ");
            int port = Convert.ToInt32(Console.ReadLine());
            IPEndPoint ie = new IPEndPoint(IPAddress.Parse(ipadd), port); // 服务器的IP和端口
            try
            {
                // 因为客户端只是用来向特定的服务器发送信息,所以不需要绑定本机的IP和端口。不需要监听。
                newclient.Connect(ie);
            }
            catch (SocketException e)
            {
                Console.WriteLine(" unable to connect to server ");
                Console.WriteLine(e.ToString());
                return;
            }
            int receivedDataLength = newclient.Receive(data);
            string stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength);
            Console.WriteLine(stringdata);
            while (true)
            {
                string input = Console.ReadLine();
                if (input == " exit ")
                    break;
                newclient.Send(Encoding.ASCII.GetBytes(input));
                data = new byte[1024];
                receivedDataLength = newclient.Receive(data);
                stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength);
                Console.WriteLine(stringdata);
            }
            Console.WriteLine(" disconnect from sercer ");
            newclient.Shutdown(SocketShutdown.Both);
            newclient.Close();
        }
    }
}

上面的服务端和客户端都是控制台应用程序, 想办法做一个窗体类型的, 思路就是另起一个线程, 这个线程专门负责两端建立连接. 如果不采用另起线程的方法, 当等待连接而没有连接上, 或者主动连接, 服务端还没有相应时, 程序就会出现没有响应的假死状态.

当这个线程将两个端口连接成功后, 就让程序进入一个死循环, 这个死循环负责不断的接收是否有消息传来, 传来的话就在txtGetMsg中显示出来:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
while (true)    // 用死循环来不断的获取信息
{
    data = new byte[1024];
    recv = newclient.Receive(data);
 
    uiContext.Send(new SendOrPostCallback(
    state =>
    {
        int txtGetMsgLength = txtGetMsg.Text.Length;
        string recMsg = "Friend:       " + System.DateTime.Now.ToString() + "\n    " +Encoding.Unicode.GetString(data, 0, recv) + "\n";
        txtGetMsg.AppendText(recMsg);
        txtGetMsg.Select(txtGetMsgLength, recMsg.Length - Encoding.Unicode.GetString(data, 0, recv).Length - 1);
        txtGetMsg.SelectionColor = Color.Red;
    }), null);
}

如果按下发送消息的按钮, 则发送txtSendMsg中的文本, 我写的是用Unicode编码, 所以可以发送中文字符.

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private void btnSendMsg_Click(object sender, EventArgs e)
{
    string input = txtSendMsg.Text;
    if (input == "")
    {
        MessageBox.Show("消息不能为空!", "发送消息出错");
        txtSendMsg.Focus();
    }
    else
    {
        if (meIsClient)
        {
            newclient.Send(Encoding.Unicode.GetBytes(input));
            string showText = "Me:           " + System.DateTime.Now.ToString() + "\n    "
            + input + "\n";
            int txtGetMsgLength = txtGetMsg.Text.Length;
            txtGetMsg.AppendText(showText);
            txtGetMsg.Select(txtGetMsgLength, showText.Length - 1 - input.Length);
            txtGetMsg.SelectionColor = Color.Blue;
            txtSendMsg.Text = "";
        }
        else
        {
            client.Send(Encoding.Unicode.GetBytes(input));
            string showText = "Me        " + System.DateTime.Now.ToString() + "\n    "
            + input + "\n";
            int txtGetMsgLength = txtGetMsg.Text.Length;
            txtGetMsg.AppendText(showText);
            txtGetMsg.Select(txtGetMsgLength, showText.Length - 1 - input.Length);
            txtGetMsg.SelectionColor = Color.Blue;
            txtSendMsg.Text = "";
        }
    }
}

程序的运行效果

下载地址: /Files/technology/局域网聊天工具.zip

用Socket做一个局域网聊天工具(转)的更多相关文章

  1. 用c#写的一个局域网聊天客户端 类似小飞鸽

    用c#写的一个局域网聊天客户端 类似小飞鸽 摘自: http://www.cnblogs.com/yyl8781697/archive/2012/12/07/csharp-socket-udp.htm ...

  2. Python使用Socket写一个简单聊天程序

    b2b模式的聊天工具 服务端: # 链接 while True: print('等待连接...') sock,adr = server_socket.accept() while True: try: ...

  3. 通过socket和Udp协议简单实现一个群体聊天工具(控制台)

    编写一个聊天程序.有收数据的部分 和 发数据的部分.这两个部分需要同时执行,这就用到多线程技术,一个线程负责收,一个现象负责发. 因为收和发动作是不一致的,所以要定义两个run方法而且这两个方法要封装 ...

  4. nodeJS+express+Jade写一个局域网聊天应用(node基础)

    为了复习一下nodeJS, 而且socketIO这东西听起来就好高端有木有, 而且有人写过了open, 也可以作为自己的参考有木有, 点击下载源代码: express是4.x的版本, 跟以前的配置有些 ...

  5. 使用socket搭建一个网络聊天室

    #服务器端import socket import threading #创建一个TCP端 sock = socket.socket(socket.AF_INET, socket.SOCK_STREA ...

  6. TCPIP协议编程:基于UDP协议的局域网聊天工具的研发

    任务目标 聊天器采用客户端/服务器(C/S)模式: 客户端利用UDP与服务器相连,客户端与客户端之间通过UDP相互通信: 服务器端具有服务器端口设置维护客户端个人信息,记录客户端状态,分配账号等: 客 ...

  7. 学习WebSocket(二):使用Spring WebSocket做一个简单聊天室

    聊天室高频率.低延时完全符合websocket的特点,所以聊天室使用websocket再适合不过了. 聊天室的功能并没有比上一节代码多多少,主要在握手阶段对用户的session做处理,对用户的消息进行 ...

  8. 关于yum网络版仓库(本地yum仓库的安装配置,如果没网了,做一个局域网内的yum仓库)

    2017-11-13 22:49:48 1:两种方式:   a.每一台机器都配一个本地文件系统上的yum仓库 file:///packege/path/ b.在局域网内部配置一台节点(server-b ...

  9. C#局域网聊天工具_UDP广播

    接上一讲,程序启动就要发送广播消息,如何发送广播消息,这一讲将给大家好好讲讲网络广播的知识,以及C#如何实现广播. 第一部分.什么是广播地址,以及广播地址怎么计算 1.1 广播地址是什么? 主机号全为 ...

随机推荐

  1. 【温故知新C/C++/opencv】取址符&||cv::groupRectangles||引用与值传递

    cv::groupRectangles void groupRectangles(vector<Rect>& rectList, int groupThreshold, doubl ...

  2. ios上传应用后,审核流程完成前(reveiw)修改了程序内容,如何上传替换

    其实挺简单,只需要更改下version和build版本 看图说话就可以.我的程序之前版的版本设置 修改bug之后的设置: 然后重新打包就好了,提示打包成功后,在itunesconnect查看发现 选中 ...

  3. Javascript基础--类与对象(五)

    js面向(基于)对象编程1.澄清概念 1.1 js中基于对象 == js 面向对象 1.2 js中没有类class,但是它取了一个新的名字,交原型对象,因此 类 = 原型对象. 2.为什么需要对象? ...

  4. 《day11---内部类&匿名内部类》

    //79-80-面向对象-内部类-体现 /* 当A类中的内容要被B类直接访问,而A类还需要去创建B类的对象,访问B的内容时, 这时可以将B类定义到A类的内部,这样访问更为便捷. 将B类称之为内部类(内 ...

  5. uitabbarcontroller中 在设置tab bar item的image属性后不显示问题

    开始使用ios中的UITabBarController,在给Tab Bar Item设置自定义图片的时候,遇到了问题 按照如下配置: 出来的结果确是: 实际上test24.png应该是: 纠结了很久, ...

  6. JS原生回到顶部效果

    // 回到顶部 onload = function () { var oBtnTop = document.getElementById('toTop'); var timer = null; oBt ...

  7. oracle触发器如何使用2

    触发器 是特定事件出现的时候,自动执行的代码块.类似于存储过程,但是用户不能直接调用他们.触发器是许多关系数据库系统都提供的一项技术.在ORACLE系统里,触发器类似过程和函数,都有声明,执行和异常处 ...

  8. jQuery之$('#id')和$('#'+id)

    最近在项目中使用$('#id')时,发现拿到的元素怎么都是空元素,(前提是id是作为变量),纠结了好一阵,使用fire bug也调试了半天终于发现原来$('#id')是使用整体来匹配,即查找id 为i ...

  9. poj蚂蚁问题

    问题描述: n只蚂蚁以每秒1cm的速度在长为Lcm的竿子上爬行.当蚂蚁爬到竿子的端点时就会掉落.由于竿子太细,两只蚂蚁相遇时,它们不能交错通过,只能各自反向 爬回去.对于每只蚂蚁,我们知道它距离竿子左 ...

  10. 安装VMware Tools找不到内核头文件

    http://blog.csdn.net/bobbat/article/details/38568885 安装VMware Tools,解决无法找到kernel header path的问题 安装 V ...