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.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Socket服务端
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

    //存储客户端IP与Socket的键值对集合
    Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
    /// <summary>
    /// 开始监听按钮
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            //1.创建一个监听的Socket
            Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            
            //2.创建IP地址和端口号对象
            IPAddress ip = IPAddress./*Any;//*/Parse(textIP.Text);
            IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(textPort.Text));
            
            //3.让负责监听的Socket绑定IP以及端口号
            socketWatch.Bind(point);
            ShowMdg("监听成功");
            
            //4.监听队列
            socketWatch.Listen(10);
            
            //5.创建负责监听的Socket,来接受客户端的连接, 创建与客户端通信的Socket (需要在子线程中循环执行)
            Thread th = new Thread(Listen);
            th.IsBackground = true;
            th.Start(socketWatch);
        }
        catch
        { }

    }
    /// <summary>
    ///监听方法
    /// </summary>
    /// <param name="o">主进程中创建的负责监听的Socket以object形式传入</param>
    private void Listen(object o)
    {
        //转为Socket类的对象(里式转换)
        Socket socketWatch = o as Socket;
        while (true)//循环监听客户端的接入,为其创建负责与之通信的Socket对象,并以IP,Socket对象的键值对形式将其加入列表
        {
            try
            {
                Socket socketSend = socketWatch.Accept();//5.次方法会一直等待客户端进行连接需在子线程中执行
                dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);//客户端连接到服务器时将其IP地址与负责通信的Socket存入字典集合
                //将远程客户端的IP地址端口号存到下拉菜单中
                comboBox1.Items.Add(socketSend.RemoteEndPoint.ToString());
                ShowMdg(socketSend.RemoteEndPoint.ToString() + "连接成功");//显示远程客户端及端口号

                //6.客户端连接成功后,服务器接收客户端发来的消息 (子线程中循环执行)
                Thread th = new Thread(Receive);
                th.IsBackground = true;
                th.Start(socketSend);
            }catch
            { }
        }
    }
    /// <summary>
    /// 服务器端不停接收客户端发来的消息
    /// </summary>
    /// <param name="o">子线程中创建的负责与此客户端收发数据的Socket对象</param>
    private void Receive(object o)
    {
        Socket socketSend = o as Socket;
        while (true)//不断接受客户端发来的消息
        {
            try
            {
                byte[] date = new byte[1024 * 1024 * 2];//字节数组容器:接收发来的消息
                int r = socketSend.Receive(date);
                if (r == 0)//客户端退出收到的字节数为0时结束循环,不再接收此客户端消息
                    break;
                string s = Encoding.UTF8.GetString(date, 0, r);
                ShowMdg(socketSend.RemoteEndPoint.ToString() + ":" + s);
            }
            catch
            { }//为空:出现异常时不进行反馈
        }
    }

    private void ShowMdg(string date)
    {
        textLog.AppendText(date + "\r\n");
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Control.CheckForIllegalCrossThreadCalls=false;//取消跨线程检测
    }
    /// <summary>
    /// 服务器向客户端发送消息
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btn_Send_Click(object sender, EventArgs e)
    {
        string message = textMsg.Text;//向客户端传输的信息
        byte[] data = Encoding.UTF8.GetBytes(message);//对一个字符串做编码,转为字节数组
        //获取用户在下拉菜单中选中的IP地址(服务器给指定客户端发送消息)
        string ip = comboBox1.SelectedItem.ToString();
        dicSocket[ip].Send(data);

        //向每个客户端发送消息
        /*foreach (KeyValuePair<string ,Socket> soc in dicSocket)
        {
            soc.Value.Send(data);
        }*/
    }
}

}