News for 十二月 2009

RLE编码算法


  2 // RLEDlg.cpp : 实现文件
  3 //
  4 
  5 #include stdafx.h
  6 #include RLE.h
  7 #include RLEDlg.h
  8 
  9 #ifdef _DEBUG
 10 #define new DEBUG_NEW
 11 #endif
 12 
 13 struct repeate
 14 {
 15     int name;
 16     int num ;
 17 }all[8][8];
 18 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
 19 
 20 //判断该数是否存在
 21 int isExistInArray(int b,int j)
 22 {
 23     for (int i=0;i<8;i++)
 24     {
 25         if (all[j][i].name==b)
 26         {
 27             return i;
 28         }
 29     }
 30     return -1;
 31 }
 32 
 33 
 34 class CAboutDlg : public CDialog
 35 {
 36 public:
 37     CAboutDlg();
 38 
 39 // 对话框数据
 40     enum { IDD = IDD_ABOUTBOX };
 41 
 42     protected:
 43     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
 44 
 45 // 实现
 46 protected:
 47     DECLARE_MESSAGE_MAP()
 48 };
 49 
 50 CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
 51 {
 52 }
 53 
 54 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
 55 {
 56     CDialog::DoDataExchange(pDX);
 57 }
 58 
 59 BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
 60 END_MESSAGE_MAP()
 61 
 62 
 63 // CRLEDlg 对话框
 64 
 65 
 66 
 67 
 68 CRLEDlg::CRLEDlg(CWnd* pParent /*=NULL*/)
 69     : CDialog(CRLEDlg::IDD, pParent)
 70 {
 71     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 72 }
 73 
 74 void CRLEDlg::DoDataExchange(CDataExchange* pDX)
 75 {
 76     CDialog::DoDataExchange(pDX);
 77 }
 78 
 79 BEGIN_MESSAGE_MAP(CRLEDlg, CDialog)
 80     ON_WM_SYSCOMMAND()
 81     ON_WM_PAINT()
 82     ON_WM_QUERYDRAGICON()
 83     //}}AFX_MSG_MAP
 84     ON_BN_CLICKED(IDC_BTN_GET_ORIGION, &CRLEDlg::OnBnClickedBtnGetOrigion)
 85     ON_BN_CLICKED(IDC_GETRLE, &CRLEDlg::OnBnClickedGetrle)
 86 END_MESSAGE_MAP()
 87 
 88 
 89 // CRLEDlg 消息处理程序
 90 
 91 BOOL CRLEDlg::OnInitDialog()
 92 {
 93     CDialog::OnInitDialog();
 94 
 95     // 将“关于…”菜单项添加到系统菜单中。
 96 
 97     // IDM_ABOUTBOX 必须在系统命令范围内。
 98     ASSERT((IDM_ABOUTBOX & 0xFFF0== IDM_ABOUTBOX);
 99     ASSERT(IDM_ABOUTBOX < 0xF000);
100 
101     CMenu* pSysMenu = GetSystemMenu(FALSE);
102     if (pSysMenu != NULL)
103     {
104         BOOL bNameValid;
105         CString strAboutMenu;
106         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
107         ASSERT(bNameValid);
108         if (!strAboutMenu.IsEmpty())
109         {
110             pSysMenu->AppendMenu(MF_SEPARATOR);
111             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
112         }
113     }
114 
115     // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
116     //  执行此操作
117     SetIcon(m_hIcon, TRUE);            // 设置大图标
118     SetIcon(m_hIcon, FALSE);        // 设置小图标
119 
120     // TODO: 在此添加额外的初始化代码
121 
122     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
123 }
124 
125 void CRLEDlg::OnSysCommand(UINT nID, LPARAM lParam)
126 {
127     if ((nID & 0xFFF0== IDM_ABOUTBOX)
128     {
129         CAboutDlg dlgAbout;
130         dlgAbout.DoModal();
131     }
132     else
133     {
134         CDialog::OnSysCommand(nID, lParam);
135     }
136 }
137 
138 // 如果向对话框添加最小化按钮,则需要下面的代码
139 //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
140 //  这将由框架自动完成。
141 
142 void CRLEDlg::OnPaint()
143 {
144     if (IsIconic())
145     {
146         CPaintDC dc(this); // 用于绘制的设备上下文
147 
148         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
149 
150         // 使图标在工作区矩形中居中
151         int cxIcon = GetSystemMetrics(SM_CXICON);
152         int cyIcon = GetSystemMetrics(SM_CYICON);
153         CRect rect;
154         GetClientRect(&rect);
155         int x = (rect.Width() - cxIcon + 1/ 2;
156         int y = (rect.Height() - cyIcon + 1/ 2;
157 
158         // 绘制图标
159         dc.DrawIcon(x, y, m_hIcon);
160     }
161     else
162     {
163         CDialog::OnPaint();
164     }
165 }
166 
167 //当用户拖动最小化窗口时系统调用此函数取得光标
168 //显示。
169 HCURSOR CRLEDlg::OnQueryDragIcon()
170 {
171     return static_cast<HCURSOR>(m_hIcon);
172 }
173 
174 //获取默认图像
175 void CRLEDlg::OnBnClickedBtnGetOrigion()
176 {
177     // TODO: 在此添加控件通知处理程序代码
178     for (int i = 1009;i <= 1072++i)
179     {
180         if (i<1017)
181         {
182             GetDlgItem(i)->SetWindowText(L5);
183         }
184         else if (i<1021)
185         {
186             GetDlgItem(i)->SetWindowText(L6);
187         }
188         else if (i<1030)
189         {
190             GetDlgItem(i)->SetWindowText(L9);
191         }
192         else if (i< 1035)
193         {
194             GetDlgItem(i)->SetWindowText(L8);
195         }
196         else if (i<1041)
197         {
198             GetDlgItem(i)->SetWindowText(L7);
199         }
200         else if (i<1049)
201         {
202             GetDlgItem(i)->SetWindowText(L4);
203         }
204         else if (i<1054)
205         {
206             GetDlgItem(i)->SetWindowText(L6);
207         }
208         else if (i<1060)
209         {
210             GetDlgItem(i)->SetWindowText(L3);
211         }
212         else if (i<1065)
213         {
214             GetDlgItem(i)->SetWindowText(L8);
215         }
216         else if (i<1069)
217         {
218             GetDlgItem(i)->SetWindowText(L5);
219         }
220         else
221             GetDlgItem(i)->SetWindowText(L9);
222     }
223 
224 }
225 //RLE编码
226 void CRLEDlg::OnBnClickedGetrle()
227 {
228     // TODO: 在此添加控件通知处理程序代码
229     //将数组清零
230     ClearArray();
231     int number[8][8];
232     int start = 1009;
233     int temp = 0;
234     CString str;
235     int z =0;
236     CString out;
237     for (int i=0;i<8;i++)
238     {
239         for (int j=0;j<8;j++)
240         {
241             //依次取了每个控件的值
242             GetDlgItem(start)->GetWindowText(str);
243             //转换成整形
244             temp=_wtoi(str);
245             //保存至数组中
246             number[i][j]=temp;
247             start++;
248         }
249     }
250     for (int j =0;j<8;j++)
251     {
252         z = 0;
253         for (int i=0;i<8;++i)
254         {
255             int b=isExistInArray(number[j][i],j);
256             if (b!=-1)
257             {
258                 all[j][b].num++;
259             }
260             else
261             {
262                 all[j][z].name = number[j][i];
263                 all[j][z].num++;
264                 z++;
265             }
266         }
267     }
268     CString strCount;
269     for (int j=0;j<8;++j)
270     for (int i=0;i<8;++i)
271     {
272         if (all[j][i].name!=0)
273         {
274             strCount.Format(L%d,all[j][i].name);
275             out += strCount+L ;
276             strCount.Format(L%d,all[j][i].num);
277             out += strCount+L ;
278         }
279     }
280     //显示RLE结果
281     GetDlgItem(IDC_EDIT_RESULT)->SetWindowText(out);
282 }
283 //将结果清零
284 void CRLEDlg::ClearArray()
285 {
286     for (int i=0;i<8;++i)
287         for (int j=0;j<8;j++)
288         {
289             all[i][j].name =0;
290             all[i][j].num =0;
291         }
292 
293 }

 

结果截图

工程文件下载/Files/eping/RLE.rar

Edited: 十二月 20th, 2009

TCP协议的无消息边界问题

使用TCP协议编写应用程序时,需要考虑一个问题:TCP协议是无消息边界的,即不能保证来自单个Send方法的数据能被单个Receive方法读取。

eg:

第一次发送:abcdefg 第二次发送:123456 接收方接收数据时,可能会出现以下情况:

第一次接收:abcdefg123456 也可能出现:第一次接收:abc 第二次接收:efg12 第三次接收:3456

因此要解决TCP发送消息与接收消息一致性,编程时必须要解决消息边界问题。

解决办法:1、发送固定长度的消息。这种方适用于信息长度固定的场合。

2、将消息长度与消息一起发送。这种方法增加了数据传送信息量,也增加了编程工作量。

eg:每次发送的字符串信息前面用2个字节表明本次信息的长度,接收方先从这两个字节得到信息长度。然后根据长度值循环接收发送方发送的字符串

3、使用特殊标记分隔消息。这种方法适合信息本身不包含特殊标记的场合。如每发送一行信息,就可以用回车换行作为分隔符。

Edited: 十二月 12th, 2009

C#网络编程实例

客户端代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace SocketClient
{
    class Program
    {
        static void Main(string[] args)
        {
            //保存输入要发送的字符串
            string input;
            //要连接的远程IP
            IPAddress remoteHost = IPAddress.Parse(“172.16.86.90″);
            //IP地址跟端口的组合
            IPEndPoint iep = new IPEndPoint(remoteHost, 8080);
            //把地址绑定到Socket
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //连接远程服务器
            try
            {
                clientSocket.Connect(iep);
                Console.WriteLine(“请输入您要发送的字符串”);
                //保存输入的字符串
                input = Console.ReadLine();
                //用字节数组保存要发送的字符串
                byte[] message = System.Text.Encoding.Unicode.GetBytes(input);
                //新建一个NetworkStream对象发送数据
                NetworkStream netstream = new NetworkStream(clientSocket);
                //向服务器端发送message内容
                netstream.Write(message, 0, message.Length);
                clientSocket.Shutdown(SocketShutdown.Both);
                clientSocket.Close();
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(“服务器端连接失败”);
            }
           

          
           
        }
    }
}

服务器端代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace SocketServer
{
    class Program
    {
        static void Main(string[] args)
        {
            //本机IP
            IPAddress ip = IPAddress.Parse(“172.16.86.90″);
            //IP地址跟端口的组合
            IPEndPoint iep = new IPEndPoint(ip, 8080);
            //创建Socket
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //绑定Socket
            socket.Bind(iep);
            //服务器已经做好接收任何连接的准备
            socket.Listen(10);
            while (true)
            {
                //执行accept方法
                Socket Client = socket.Accept();
                byte[] message = new byte[1024];
                NetworkStream networkStream = new NetworkStream(Client);
                int len = networkStream.Read(message, 0, message.Length);
                //byte数组转换成string
                string output = System.Text.Encoding.Unicode.GetString(message);
                Console.WriteLine(“一共从客户端接收了” + len.ToString() + “字节。接收字符串为:”+output);    
            }
           

           
        }
    }
}

Edited: 十二月 11th, 2009

C#网络编程这Socket

System.Net.Sockets   包含了一个socket类,Socket原型

Socket(AddressFamily af,SocketType st,ProtocolType pt)  AddressFamily 为网络类型,SocketType 为数据类型,ProtocolType 为使用的网络协议

AddressFamily 总是使用AddressFamily.InterNetwork枚举值。

SocketType 参数则与ProtocolType 参数配合使用,不允许其他的形式。

SocketType ProtocolType 说明
Dgram Udp 无连接通信
Stream Tcp 面向连接的通信
Raw Icmp Internet控制报文协议
Raw Raw 简单IP包通信

Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

套接字常用属性

属性 说明
Avilable 获取准备读取的数据数量
Blocking 获取或设置套接字是否处于阻塞模式
Connected 获取一个值,该值表明套接字是否连接到远程设备
LocalEndPoint 获取套接字的本地EndPoint对象
RemoteEndPoint 获取套接字的远程EndPoint对象

Edited: 十二月 10th, 2009

特殊IP地址

Any Address:0.0.0.0  代表本地系统可用的任何IP地址(当系统有多个网络接口,而不想把套接字绑定到任何特定接口的时候,就可以使用这个地址)

Broadcast Address:255.255.255.255  代表本地网络的IP广播地址

(一般用于当系统想创建一个伪套接字,而且不想把它绑定到任何接口的时候)
Loopback Address:127.0.0.1 代表系统的回送地址
None Address:255.255.255.255  代表系统上没有网络的接口

Edited: 十二月 10th, 2009