系统功能基本要求

  • 通讯录信息

    -通讯人姓名

    -联系方式

    -工作地点

    -城市

    -备注
  • 备忘录信息

    -包括什么时间

    -事件

    -地点
  • 日记信息

    -时间

    -地点

    -事情

    -人物

    -个人财物管理

    -总收入

    -消费项目

    -消费金额

    -消费时间

    -剩余资金

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. GUI(GroupLayout 分组布局)

    组:一些组件的集合                       连续组:一个接着一个摆放                       并行组:一个组在另一个组的顶部                   ...

  2. 201521123115 《Java程序设计》第4周学习总结

    1.本周学习总结 2.书面作业 1.注释的作用 2.面向对象设计 2.1将在网上商城购物或者在班级博客进行学习这一过程,描述成一个故事.(不得少于50字,参考QQ群中PPT的范例). 感觉自己在代码方 ...

  3. 201521123021《Java程序设计》第1周学习总结

    1. 本章学习总结 1.第一次接触Java,初步了解Java的运行环境,学会了安装eclipse和JDK,解决了在安装中的path变量的设置问题. 2.知道了jvm,jre,jdk的区别,jdk是一个 ...

  4. 201521123042 《Java程序设计》第12周学习总结

    本次作业参考文件 正则表达式参考资料 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对象(属性:int id, String ...

  5. JAVA课程设计+五子棋(个人博客)

    1.团队博客地址: http://www.cnblogs.com/yzb123/p/7063424.html 2.个人负责模块或任务说明 游戏初始化,清除棋盘上的棋子 鼠标监听器 棋子落棋 判断胜负 ...

  6. 201521123027 <java程序设计>第九周学习总结

    1.本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2.书面作业 Q1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前编写的代码中经常出现什 ...

  7. eclipse : java项目中的web.xml( Deployment Descriptor 部署描述文件 )配置说明

    context-param.listener.filter.servlet  首先可以肯定的是,加载顺序与它们在 web.xml 配置文件中的先后顺序无关.即不会因为 filter 写在 listen ...

  8. Hibernate第四篇【集合映射、一对多和多对一】

    前言 前面的我们使用的是一个表的操作,但我们实际的开发中不可能只使用一个表的-因此,本博文主要讲解关联映射 集合映射 需求分析:当用户购买商品,用户可能有多个地址. 数据库表 我们一般如下图一样设计数 ...

  9. 渗透相关website

    开源安全测试方法论:http://www.isecom.org/research/osstmm.html 信息系统安全评估框架:www.oissg.org/issaf 开放式web应用程序安全项目(O ...

  10. AngularJS -- 指令(创建自定义指令)

    点击查看AngularJS系列目录 转载请注明出处:http://www.cnblogs.com/leosx/   什么是指令 注:本指南是针对已经熟悉AngularJS基础知识的开发人员.如果你才刚 ...