系统功能基本要求

  • 通讯录信息

    -通讯人姓名

    -联系方式

    -工作地点

    -城市

    -备注
  • 备忘录信息

    -包括什么时间

    -事件

    -地点
  • 日记信息

    -时间

    -地点

    -事情

    -人物

    -个人财物管理

    -总收入

    -消费项目

    -消费金额

    -消费时间

    -剩余资金

wpf局域网通信

wpf局域网聊天

想到做一个c/s,传输我就想到了json

json需要先安装nuget中Newtonsoft.Json;



安装

因为要找比较多,可以搜索



然后在文件写using Newtonsoft.Json;

把类转json

JsonConvert.SerializeObject(obj)

把json转类

        private T Deserialize<T>(string str)
        {
            try
            {
                T temp = JsonConvert.DeserializeObject<T>(str);
                return temp;
            }
            catch (JsonException e)
            {
                reminder = "输入不是ObservableCollection<T> json" + e.Message;
            }
            return default(T);
        }

参考很多博客写出了局域网传输的代码

服务器:

    public class principal_Computer
    {
        public principal_Computer(System.Action<string> ReceiveAction)
        {
            this.ReceiveAction = ReceiveAction;

            ServerSocket = new Socket(AddressFamily.InterNetwork , SocketType.Stream , ProtocolType.Tcp);
            IPAddress ip = IPAddress.Any;
            ServerInfo = new IPEndPoint(ip , port);
            ServerSocket.Bind(ServerInfo);//将SOCKET接口和IP端口绑定
            ServerSocket.Listen(10);//开始监听,并且挂起数为10

            ClientSocket = new Socket[65535];//为客户端提供连接个数
            ClientNumb = 0;//数量从0开始统计

            ServerThread = new Thread(new ThreadStart(RecieveAccept));//将接受客户端连接的方法委托给线程
            ServerThread.Start();//线程开始运行
        }

        public void send(string str)
        {
            byte[] MsgBuffer = encoding.GetBytes(str);
            for (int i = 0; i < ClientNumb; i++)
            {
                if (ClientSocket[i].Connected)
                {
                    //回发数据到客户端
                    ClientSocket[i].Send(MsgBuffer , 0 , MsgBuffer.Length , SocketFlags.None);
                }
            }
        }

        //接受客户端连接的方法
        private void RecieveAccept()
        {
            while (true)
            {
                //Accept 以同步方式从侦听套接字的连接请求队列中提取第一个挂起的连接请求,然后创建并返回新的 Socket。
                //在阻止模式中,Accept 将一直处于阻止状态,直到传入的连接尝试排入队列。连接被接受后,原来的 Socket 继续将传入的连接请求排入队列,直到您关闭它。
                byte[] buffer = new byte[65535];
                ClientSocket[ClientNumb] = ServerSocket.Accept();
                ClientSocket[ClientNumb].BeginReceive(buffer , 0 , buffer.Length , SocketFlags.None ,
                new AsyncCallback(RecieveCallBack) , ClientSocket[ClientNumb]);
                ReceiveAction(encoding.GetString(buffer));
                ClientNumb++;
            }
        }

        //回发数据给客户端
        private void RecieveCallBack(IAsyncResult AR)
        {
            try
            {
                Socket RSocket = (Socket)AR.AsyncState;
                    byte[] MsgBuffer = new byte[65535];
                    //同时接收客户端回发的数据,用于回发
                    RSocket.BeginReceive(MsgBuffer , 0 , MsgBuffer.Length , SocketFlags.None , ar =>
                    {
                        try
                        {
                            RSocket.EndReceive(ar);
                            ReceiveAction(encoding.GetString(MsgBuffer).Trim('\0' , ' '));
                            RecieveCallBack(ar);
                        }
                        catch (SocketException e)
                        {
                            ReceiveAction("对方断开连接" + e.Message);
                        }

                    } , RSocket);

            }
            catch
            {
            }

        }

        private IPEndPoint ServerInfo;//存放服务器的IP和端口信息
        private Socket ServerSocket;//服务端运行的SOCKET
        private Thread ServerThread;//服务端运行的线程
        private Socket[] ClientSocket;//为客户端建立的SOCKET连接
        private int ClientNumb;//存放客户端数量
        //private byte[] MsgBuffer;//存放消息数据
        private int port = 54321; //端口号
        private System.Action<string> ReceiveAction;
        private Encoding encoding = Encoding.Default;

    }

客户端

    public class slaveComputer
    {
        public slaveComputer(System.Action<string> ReceiveAction)
        {
            this.ReceiveAction = ReceiveAction;
            //定义一个IPV4,TCP模式的Socket
            ClientSocket = new Socket(AddressFamily.InterNetwork , SocketType.Stream , ProtocolType.Tcp);
        }
        public void access(string ip)
        {
            ServerInfo = new IPEndPoint(IPAddress.Parse(ip) , port);
            //客户端连接服务端指定IP端口,Sockket
            ClientSocket.Connect(ServerInfo);
            //将用户登录信息发送至服务器,由此可以让其他客户端获知
            ClientSocket.Send(encoding.GetBytes(" 进入系统!\n"));
            //开始从连接的Socket异步读取数据。接收来自服务器,其他客户端转发来的信息
            //AsyncCallback引用在异步操作完成时调用的回调方法
            ReceiveCallBack(ReceiveAction);
        }

        public void send(string str)
        {
           byte[] buffer = encoding.GetBytes(str);
            ClientSocket.Send(buffer , 0 , buffer.Length , SocketFlags.None);
        }
        private IPEndPoint ServerInfo;
        private Socket ClientSocket;
        private Encoding encoding = Encoding.Default;
        private System.Action<string> ReceiveAction;
        private void ReceiveCallBack(System.Action<string> ReceiveAction)
        {
            try
            {
                //结束挂起的异步读取,返回接收到的字节数。 AR,它存储此异步操作的状态信息以及所有用户定义数据
                byte[] MsgBuffer = new byte[65535];
                ClientSocket.BeginReceive(MsgBuffer , 0 , MsgBuffer.Length , SocketFlags.None , ar =>
                {
                    //对方断开连接时, 这里抛出Socket Exception
                    //An existing connection was forcibly closed by the remote host
                    try
                    {

                        ClientSocket.EndReceive(ar);
                        ReceiveAction(encoding.GetString(MsgBuffer).Trim('\0' , ' '));
                        ReceiveCallBack(ReceiveAction);
                    }
                    catch (SocketException e)
                    {
                        ReceiveAction("对方断开连接" + e.Message);
                    }

                } /*new AsyncCallback(ReceiveCallBack)*/ , null);

            }
            catch
            {

            }
        }
        private int port = 54321; //端口号

    }

使用方法是

写出一个private System.Action<string> ReceiveAction;



初始化

            ReceiveAction = str =>
            {
                //因为接受使用byte[] 会有很多空的字符,去掉就是消息
                string temp= str.Trim('\0' , ' ');
                if (!string.IsNullOrEmpty(temp))
                {
                    //reminder是提示的字符串
                    reminder = temp;
                }
            };

使用服务器

 var _principal_Computer = new principal_Computer(ReceiveAction);

使用客户端

            var _slaveComputer = new slaveComputer(ReceiveAction);
            _slaveComputer.access(ip);

客户端和服务器发送都是使用send

而服务器有多个客户端,发送可以指明发送到哪个客户端,可以全发送。

发送信息时,对信息进行一个类转json

因为发送信息不知道需要做什么,于是做了一个枚举,一个类

 /// <summary>
    /// 发送消息
    /// </summary>
    public class ctransmitter
    {
        public ctransmitter(int id , ecommand command , string str/*,int ran*/)
        {
            this.id = id.ToString();
            this.command = command.ToString();
            this.str = str;
            //this.ran = ran.ToString();
        }

        public string id
        {
            set;
            get;
        }
        public string command
        {
            set;
            get;
        }
        public string str
        {
            set;
            get;
        }
        //public string ran
        //{
        //    set;
        //    get;
        //}
        public override string ToString()
        {
            return JsonConvert.SerializeObject(this);
        }
    }

    public enum ecommand
    {
        login,//登录
        id,//分配id
        faddressBook,//通讯录
        ce
    }

ctransmitter里面ToString把这个类转换为json,之后接收就把json转换为类,然后根据command来得到发送的命令

                ctransmitter transmitter = JsonConvert.DeserializeObject<ctransmitter>(json);
                ecommand command = (ecommand)Enum.Parse(typeof(ecommand) , transmitter.command);
                switch (command)
                {
                    case ecommand.ce:
                        reminder("收到" + transmitter.id);
                        break;
                }

客户端循环等待服务器发送的消息,收到就把信息放到一个byte[]如果byte大小不够,分为多次。

服务器把信息发送可以依靠客户端所在的id或全部发。

所有数据转换为Default

private Encoding encoding = Encoding.Default;

ClientSocket[i]存放不如使用list来存放,因为这个长度固定,在很多机器连接断开就没了,不过这个是简单的,所以用了ClientSocket[i]

端口号都被写成没法修改,这个可以放在view一个textbox来修改

生成addressBook界面

先做一个ViewModel

viewaddressBook.cs

因为需要访问_model,在构造传入viewModel初始的_model

        public viewaddressBook(model.model _model)
        {
            this._model = _model;
        }

WPF跨线程访问线程安全的数据(如解决:该类型的CollectionView不支持从调度程序线程以外的线程对其SourceCollection)

更新数据中途出现了该类型的CollectionView不支持从调度程序线程以外的线程对其SourceCollection

查到了使用invoke就可以

从输入一个string然后更新

        private void newaddressBook(string str)
        {
            try
            {
                ObservableCollection<caddressBook> temp = DeserializeObject<caddressBook>(str);

                System.Windows.Application.Current.Dispatcher.Invoke
                (() =>
                {
                    addressbook.Clear();

                    foreach (var t in temp)
                    {
                        addressbook.Add(t);
                    }
                });
            }

            catch (JsonException e)
            {
                reminder = "输入不是ObservableCollection<caddressBook> json" + e.Message;
            }
        }

读取信息null

在运行返回一个错误

null

查询了是读取有一个null

            const string id = "id";
            const string MTIME = "MTIME";
            const string PLACE = "PLACE";
            const string INCIDENT = "INCIDENT";
            const string CONTACTSID = "NAME";
            using (SqlConnection sql = new SqlConnection(connect))
            {
                sql.Open();
                using (SqlCommand cmd = new SqlCommand(strsql , sql))
                {
                    using (SqlDataReader read = cmd.ExecuteReader())
                    {
                        if (!read.HasRows)
                            return diary;
                        int idindex = read.GetOrdinal(id);
                        int MTIMEindex = read.GetOrdinal(MTIME);
                        int PLACEindex = read.GetOrdinal(PLACE);
                        int INCIDENTindex = read.GetOrdinal(INCIDENT);
                        int CONTACTSIDindex = read.GetOrdinal(CONTACTSID);
                        while (read.Read())
                        {
                            diary.Add(new cdiary()
                            {
                                id = read.GetInt32(idindex).ToString() ,
                                MTIME = read.GetDateTime(MTIMEindex).ToString() ,
                                PLACE = read.GetString(PLACEindex) ,
                                incident = read.GetString(INCIDENTindex) ,
                                CONTACTSID = read.GetString(CONTACTSIDindex)
                            });
                        }
                    }
                }
            }

里面有些是null

使用

PLACE = read[PLACEindex] as string;

就可以

出现了把PLACE.Trim();错误可以使用

        private string DBNullstring<T>(object obj)
        {
            try
            {
                return obj == System.DBNull.Value ? " " : ( (T)obj ).ToString();
            }
            catch
            {
                return string.Empty;
            }
        }

读取发来数据需要时间

                byte[] MsgBuffer = new byte[65535];
                ClientSocket.BeginReceive(MsgBuffer , 0 , MsgBuffer.Length , SocketFlags.None , ar =>
                {
                    //对方断开连接时, 这里抛出Socket Exception
                    //An existing connection was forcibly closed by the remote host
                    try
                    {
                        ClientSocket.EndReceive(ar);
                        ReceiveAction(encoding.GetString(MsgBuffer).Trim('\0' , ' '));
                        ReceiveCallBack(ReceiveAction);
                    }
                    catch (SocketException e)
                    {
                        reminder("对方断开连接" + e.Message);
                    }
                    catch(ObjectDisposedException e)
                    {
                        reminder (id.ToString() + "连接退出" + e.Message);
                        return;
                    }

MsgBuffer比发来信息小,那么分为多次,而在识别json会出现把字符串弄成多个,这样就出现json错误

需要在发送使用分开或使用大的buffer

连接数据库

连接数据库

$"Data Source={DataSource};Initial Catalog={InitialCatalog};Integrated Security=True";
DataSource 数据库ip
InitialCatalog 数据库名

strsql是sql语句

            using (SqlConnection sql = new SqlConnection(connect))
            {
                sql.Open();
                using (SqlCommand cmd = new SqlCommand(strsql , sql))
                {
                    using (SqlDataReader read = cmd.ExecuteReader())
                    {
                        try
                        {
                            if (!read.HasRows)
                                return null;
                            //读数据
                        }
                        catch
                        {

                        }
                    }
                }
            }

数据库获得数据

从数据库获得数据可以使用SqlDataReader read = cmd.ExecuteReader()

读取read的内容

连接

            const string addressBookname = "vaddressbook";
            string sqlAddressBook = $"{usesql}{line}SELECT * FROM {addressBookname};";

使用read[str]可以获得所在数据,

            const string id = "id";
            const string name = "name";
            const string contact = "contact";
            const string caddress = "caddress";
            const string city = "city";
            const string comment = "comment";

获得字符串所在

                        int idindex = read.GetOrdinal(id);
                        int nameindex = read.GetOrdinal(name);
                        int contactindex = read.GetOrdinal(contact);
                        int caddressindex = read.GetOrdinal(caddress);
                        int cityindex = read.GetOrdinal(city);
                        int commentindex = read.GetOrdinal(comment);
                             caddressBook temp = new caddressBook
                            {
                                id = read.GetInt32(idindex).ToString() ,
                                name = read.GetString(nameindex).Trim() ,
                                contact = read.GetString(contactindex).Trim() ,
                                address = read.GetString(caddressindex).Trim() ,
                                city = read.GetString(cityindex).Trim() ,
                                comment = read.GetString(commentindex).Trim()
                            };

这种 方法使用比较难,因为需要写很多字符串和int。

对string可以直接str=read[str] as string;

发送数据

        public void send(string str)
        {
            if (ClientSocket.Connected)
            {
                byte[] buffer = encoding.GetBytes(str);
                ClientSocket.Send(buffer , 0 , buffer.Length , SocketFlags.None);
            }
            else
            {
                try
                {
                    access(ip);
                }
                catch(SocketException e)
                {
                    reminder ("连接失败 " + e.Message);
                }
                catch(InvalidOperationException e)
                {
                    reminder("服务器没有开启"+e.Message);
                }
            }
        }

客户端可以设置ip

                <TextBlock Text="ip" />
                <TextBox Text="{Binding Path=_model.ip,Mode=TwoWay}" Width="100"/>
                <Button Content="确定" Click="确定"/>

添加通讯

        public void add()
        {
            if (accord())
            {
                foreach (var t in laddressBook)
                {
                    if (addressbook_equals(addressBook, t))
                    {
                        warn = "信息重复";
                        return;
                    }
                }
                _model.send(ecommand.addaddressBook , addressBook.ToString());
                reminder = "添加通讯";
                addressBook = new caddressBook();
            }
        }

查询可以没有输入为*

删除,判断有没修改,如果没有发送删除的类

            if (addressBook.Equals(_item))
            {
                _model.send(ecommand.daddressBook , _item.ToString());
                reminder = "删除通讯";
            }

通讯录 日记都一样,只是改了名字和一些,日记需要时间,所以判断是否存在时间,如果有,格式是否正确。

程序难在写了好多次不同的数据,这些可以合并为一个,然后修改,看到通讯录重复,没有去把重复的作为一个类,每个都写一次,如果要修改,经常出错,git可以撤销

git reset --hard id

代码:https://code.csdn.net/lindexi_gd/lindexi_gd/tree/master/%E4%B8%AA%E4%BA%BA%E4%BF%A1%E6%81%AF%E6%95%B0%E6%8D%AE%E5%BA%93

wpf C# 数据库 c/s 个人信息管理 wpf局域网通信的更多相关文章

  1. WPF老矣,尚能饭否——且说说WPF今生未来(下):安心

    在前面的上.中篇中,我们已经可以看到园子里朋友的点评“后山见! WPF就比winform好! 激情对决”.看到大家热情洋溢的点评,做技术的我也很受感动.老实说,如何在本文收笔--WPF系列文章,我很紧 ...

  2. WPF入门教程系列(二) 深入剖析WPF Binding的使用方法

    WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...

  3. “WPF老矣,尚能饭否”—且说说WPF今生未来(上):担心

    近日微软公布了最新的WPF路线图,一片热议:对于老牌控件提供商葡萄城来说,这是WPF系列控件一个重要的机遇,因此,Spread Studio for WPF产品做了一次重要更新,并随着Spread S ...

  4. WPF老矣,尚能饭否——且说说WPF今生未来(中):策略

    本文接上文<WPF老矣,尚能饭否——且说说WPF今生未来(上):担心>继续. “上篇”中部分精彩的点评: 虽然WPF不再更新了,但是基于WPF的技术还是在发展着,就比如现在的WinRT,只 ...

  5. [WPF系列]基础学习(一) WPF是什么?

    引言 学习之前,我们首先大概了解下WPF诞生的背景以及它所能解决的问题或者新颖之处.WPF作为微软新一代的用户界面技术,   WPF简介 WPF的全称是WindowsPresentationFound ...

  6. WPF快速入门系列(5)——深入解析WPF命令

    一.引言 WPF命令相对来说是一个崭新的概念,因为命令对于之前的WinForm根本没有实现这个概念,但是这并不影响我们学习WPF命令,因为设计模式中有命令模式,关于命令模式可以参考我设计模式的博文:h ...

  7. WPF快速入门系列(4)——深入解析WPF绑定

    一.引言 WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能.WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信 ...

  8. wpfのuri(让你完全明白wpf的图片加载方式以及URI写法)

    绝对 pack WPF URI pack://application:,,,/是协议:“,,,”是“///”的变体 1.资源文件 — 本地程序集 Uri uri = new Uri("pac ...

  9. WPF笔记(1.10 绘图)——Hello,WPF!

    原文:WPF笔记(1.10 绘图)--Hello,WPF! 书中的代码语法过时了,改写为以下(测试通过):         <Button>            <Button.L ...

随机推荐

  1. 团队作业4——第一次项目冲刺(Alpha版本) Day4

    借的今天有课,我们团队在课间时间开了简短的会议 2.Leangoo任务分解图: 3.会议结果,和任务分配 队员 今日进展 明日安排 林燕 试编写签到.请假功能的代码雏形 签到.请假功能成熟 王李焕 和 ...

  2. 201521123065《java程序设计》第七周学习总结

    1. 本周学习总结 1.Iterator迭代器用于遍历集合中的元素: 2.使用迭代器删除元素一定要先指向下一个元素在删除第一个元素: 3.List可以有重复对象: Set不能有重复对象: 4.Map是 ...

  3. evak购物车--课程设计(201521123037邱晓娴)

    1. 团队课程设计博客链接 团队博客 2. 个人负责模块或任务说明 1.Java (1)编写用户类Users (2)编写DBConnection类,连接数据库 (3)编写GoodsDAO类,从数据库中 ...

  4. 201521123112《Java程序设计》第13周学习总结

    1. 本周学习总结 协议的概念是网络中为了通信而建立的规则,常用的应用层协议有http,ftp等. 测试计算机之间的网络是否连通可以使用ping命令. 可以使用IP+端口号的方法来确定数据包是发给哪个 ...

  5. es6中对象的类与继承方法

    对于对象,我一直搞不清楚到底是该如何去继承,如何去书写.在熟练es6之后,终于会尝试写出来了. 代码如下: //我们假定父类为person,子类为man class person{ construct ...

  6. php memcache 扩展 php -m 与 phpinfo() 不同

    事情起因,因要升级 openssl(openssl升级这里不表) ,所以在升级后对 php 也进行了从新编译,编译成功. 发现没有安装,memcache 扩展,从新编译安装了一下,显示的安装成功,但是 ...

  7. 在Ubuntu中部署并测试Fabric 1.0 Beta

    [更新:1.0Beta已经是过去式了,现在出了1.0.0的正式版,请大家参照 http://www.cnblogs.com/studyzy/p/7437157.html  安装Fabric 1.0.0 ...

  8. birt-j脚本调试 & 动态sql的实现

    一个比较好的birt问题解决网址: http://www.myexception.cn/h/1335919.html 1,Birt的JavaScript脚本简单调试 Birt中的js脚本不能用aler ...

  9. python 部署 Restful web

    使用python web做Restful 风格,很简单,采用Flask框架轻松实现一个RESTful的服务. Restful相关介绍请查看:https://www.ibm.com/developerw ...

  10. Java简单实用方法一

    整理以前的笔记,在学习Java时候,经常会用到一些方法.虽然简单但是经常使用.因此做成笔记,方便以后查阅 这篇博文先说明构造和使用这些方法. 1,判断String类型数据是否为空 String类型的数 ...