实现openfire消息记录通常有两种方式,修改服务端和添加消息记录插件。

今天,简单的说明一下修改服务端方式实现消息记录保存功能。

实现思路

修改前:

默认的,openfire只提供保存离线记录至ofOffline表中。当发送一条消息时,判断用户是否在线,若为true,不保存消息;若为fasle,保存消息至离线消息表中。

修改后:

仿照保存离线消息,用户每发送一条消息,将消息存放在ofHistory表中,ofHistory表结构同ofOffline

实现步骤:

1.修改初始数据库文件,路径src/database/openfire_sqlserver.sql

添加ofHistory表

[sql] view plaincopyprint?

CREATE TABLE ofHistory (

username NVARCHAR(64) NOT NULL,

messageID INTEGER NOT NULL,

creationDate NVARCHAR(64) NOT NULL,

messageSize INTEGER NOT NULL,

stanza TEXT NOT NULL,

CONSTRAINT ofHistory_pk PRIMARY KEY (username, messageID)

);

CREATE TABLE ofOffline (

username NVARCHAR(64) NOT NULL,

messageID INTEGER NOT NULL,

creationDate CHAR(15) NOT NULL,

messageSize INTEGER NOT NULL,

stanza NTEXT NOT NULL,

CONSTRAINT ofOffline_pk PRIMARY KEY (username, messageID)

);

注:其他数据库修改方式雷同

2.添加保存消息方法

MessageRouter类中110行

[java] view plaincopyprint?

try {

// Deliver stanza to requested route

routingTable.routePacket(recipientJID, packet, false);

//保存消息记录dml@2013.4.15

OfflineMessageStore oms = new OfflineMessageStore();

oms.addMessage_toHistory(packet);

  1. }
  2. catch (Exception e) {
  3. log.error("Failed to route packet: " + packet.toXML(), e);
  4. routingFailed(recipientJID, packet);
  5. }

3.修改OfflineMessageStore类,添加保存消息记录方法

[java] view plaincopyprint?

/**

  • $RCSfile$
  • $Revision: 2911 $
  • $Date: 2005-10-03 12:35:52 -0300 (Mon, 03 Oct 2005) $
  • Copyright (C) 2004-2008 Jive Software. All rights reserved.
  • Licensed under the Apache License, Version 2.0 (the "License");
  • you may not use this file except in compliance with the License.
  • You may obtain a copy of the License at
    1. http://www.apache.org/licenses/LICENSE-2.0
  • Unless required by applicable law or agreed to in writing, software
  • distributed under the License is distributed on an "AS IS" BASIS,
  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  • See the License for the specific language governing permissions and
  • limitations under the License.

    */

package org.jivesoftware.openfire;

import java.io.StringReader;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.Collection;

import java.util.Date;

import java.util.List;

import java.util.Map;

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.LinkedBlockingQueue;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

import org.dom4j.DocumentException;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;

import org.jivesoftware.database.DbConnectionManager;

import org.jivesoftware.database.SequenceManager;

import org.jivesoftware.openfire.container.BasicModule;

import org.jivesoftware.openfire.event.UserEventDispatcher;

import org.jivesoftware.openfire.event.UserEventListener;

import org.jivesoftware.openfire.user.User;

import org.jivesoftware.openfire.user.UserManager;

import org.jivesoftware.util.JiveConstants;

import org.jivesoftware.util.LocaleUtils;

import org.jivesoftware.util.StringUtils;

import org.jivesoftware.util.XMPPDateTimeFormat;

import org.jivesoftware.util.cache.Cache;

import org.jivesoftware.util.cache.CacheFactory;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.xmpp.packet.JID;

import org.xmpp.packet.Message;

/**

  • Represents the user's offline message storage. A message store holds messages

  • that were sent to the user while they were unavailable. The user can retrieve

  • their messages by setting their presence to "available". The messages will

  • then be delivered normally. Offline message storage is optional, in which

  • case a null implementation is returned that always throws

  • UnauthorizedException when adding messages to the store.

  • @author Iain Shigeoka

    */

    public class OfflineMessageStore extends BasicModule implements

    UserEventListener {

    private static final Logger Log = LoggerFactory

    .getLogger(OfflineMessageStore.class);

    // 保存消息记录 dml@2013.4.16

    private static final String INSERT_HISTORY = "INSERT INTO ofHistory (username, messageID, creationDate, messageSize, stanza) "

    + "VALUES (?, ?, ?, ?, ?)";

    private static final String INSERT_OFFLINE = "INSERT INTO ofOffline (username, messageID, creationDate, messageSize, stanza) "

    + "VALUES (?, ?, ?, ?, ?)";

    private static final String LOAD_OFFLINE = "SELECT stanza, creationDate FROM ofOffline WHERE username=?";

    private static final String LOAD_OFFLINE_MESSAGE = "SELECT stanza FROM ofOffline WHERE username=? AND creationDate=?";

    private static final String SELECT_SIZE_OFFLINE = "SELECT SUM(messageSize) FROM ofOffline WHERE username=?";

    private static final String SELECT_SIZE_ALL_OFFLINE = "SELECT SUM(messageSize) FROM ofOffline";

    private static final String DELETE_OFFLINE = "DELETE FROM ofOffline WHERE username=?";

    private static final String DELETE_OFFLINE_MESSAGE = "DELETE FROM ofOffline WHERE username=? AND creationDate=?";

    private static final int POOL_SIZE = 10;

    private Cache<String, Integer> sizeCache;

    /**

    • Pattern to use for detecting invalid XML characters. Invalid XML
    • characters will be removed from the stored offline messages.

      */

      private Pattern pattern = Pattern.compile("&\#[\d]+;");

    /**

    • Returns the instance of OfflineMessageStore being used by the
    • XMPPServer.
    • @return the instance of OfflineMessageStore being used by the
      1. XMPPServer.

    */

    public static OfflineMessageStore getInstance() {

    return XMPPServer.getInstance().getOfflineMessageStore();

    }

    /**

    • Pool of SAX Readers. SAXReader is not thread safe so we need to have a
    • pool of readers.

      */

      private BlockingQueue xmlReaders = new LinkedBlockingQueue(

      POOL_SIZE);

    /**

    • Constructs a new offline message store.

      */

      public OfflineMessageStore() {

      super("Offline Message Store");

      sizeCache = CacheFactory.createCache("Offline Message Size");

      }

    /**

    • Adds a message to this message store. Messages will be stored and made
    • available for later delivery.
    • @param message
      1. the message to store.

    */

    public void addMessage(Message message) {

    if (message == null) {

    return;

    }

    // ignore empty bodied message (typically chat-state notifications).

    if (message.getBody() == null || message.getBody().length() == 0) {

    // allow empty pubsub messages (OF-191)

    if (message.getChildElement("event",

    "http://jabber.org/protocol/pubsub#event") == null) {

    return;

    }

    }

    JID recipient = message.getTo();

    String username = recipient.getNode();

    // If the username is null (such as when an anonymous user), don't

    // store.

    if (username == null

    || !UserManager.getInstance().isRegisteredUser(recipient)) {

    return;

    } else if (!XMPPServer.getInstance().getServerInfo().getXMPPDomain()

    .equals(recipient.getDomain())) {

    // Do not store messages sent to users of remote servers

    return;

    }

    1. long messageID = SequenceManager.nextID(JiveConstants.OFFLINE);
    2. // Get the message in XML format.
    3. String msgXML = message.getElement().asXML();
    4. Connection con = null;
    5. PreparedStatement pstmt = null;
    6. try {
    7. con = DbConnectionManager.getConnection();
    8. pstmt = con.prepareStatement(INSERT_OFFLINE);
    9. pstmt.setString(1, username);
    10. pstmt.setLong(2, messageID);
    11. pstmt.setString(3, StringUtils.dateToMillis(new java.util.Date()));
    12. // SimpleDateFormat df = new
    13. // SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    14. // pstmt.setString(3, df.format(new Date()).toString());
    15. pstmt.setInt(4, msgXML.length());
    16. pstmt.setString(5, msgXML);
    17. pstmt.executeUpdate();
    18. }
    19. catch (Exception e) {
    20. Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
    21. } finally {
    22. DbConnectionManager.closeConnection(pstmt, con);
    23. }
    24. // Update the cached size if it exists.
    25. if (sizeCache.containsKey(username)) {
    26. int size = sizeCache.get(username);
    27. size += msgXML.length();
    28. sizeCache.put(username, size);
    29. }

    }

    /**

    • 保存消息记录

    • @author dml

    • @param message

      */

      public void addMessage_toHistory(Message message) {

      if (message == null) {

      return;

      }

      // ignore empty bodied message (typically chat-state notifications).

      if (message.getBody() == null || message.getBody().length() == 0) {

      // allow empty pubsub messages (OF-191)

      if (message.getChildElement("event",

      "http://jabber.org/protocol/pubsub#event") == null) {

      return;

      }

      }

      JID recipient = message.getTo();

      String username = recipient.getNode();

      // If the username is null (such as when an anonymous user), don't

      // store.

      if (username == null

      || !UserManager.getInstance().isRegisteredUser(recipient)) {

      return;

      } else if (!XMPPServer.getInstance().getServerInfo().getXMPPDomain()

      .equals(recipient.getDomain())) {

      // Do not store messages sent to users of remote servers

      return;

      }

      long messageID = SequenceManager.nextID(JiveConstants.OFFLINE);

      // Get the message in XML format.

      String msgXML = message.getElement().asXML();

      Connection con = null;

      PreparedStatement pstmt = null;

      try {

      con = DbConnectionManager.getConnection();

      pstmt = con.prepareStatement(INSERT_HISTORY);

      pstmt.setString(1, username);

      pstmt.setLong(2, messageID);

      // pstmt.setString(3, StringUtils.dateToMillis(new

      // java.util.Date()));

      SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

      pstmt.setString(3, df.format(new Date()).toString());

      1. pstmt.setInt(4, msgXML.length());
      2. pstmt.setString(5, msgXML);
      3. pstmt.executeUpdate();

      }

      catch (Exception e) {

      Log.error(LocaleUtils.getLocalizedString("admin.error"), e);

      } finally {

      DbConnectionManager.closeConnection(pstmt, con);

      }

      // Update the cached size if it exists.

      if (sizeCache.containsKey(username)) {

      int size = sizeCache.get(username);

      size += msgXML.length();

      sizeCache.put(username, size);

      }

      }

    /**

    • Returns a Collection of all messages in the store for a user. Messages

    • may be deleted after being selected from the database depending on the

    • delete param.

    • @param username

      1. the username of the user who's messages you'd like to receive.
    • @param delete

      1. true if the offline messages should be deleted.
    • @return An iterator of packets containing all offline messages.

      */

      public Collection getMessages(String username,

      boolean delete) {

      List messages = new ArrayList();

      SAXReader xmlReader = null;

      Connection con = null;

      PreparedStatement pstmt = null;

      ResultSet rs = null;

      try {

      // Get a sax reader from the pool

      xmlReader = xmlReaders.take();

      con = DbConnectionManager.getConnection();

      pstmt = con.prepareStatement(LOAD_OFFLINE);

      pstmt.setString(1, username);

      rs = pstmt.executeQuery();

      while (rs.next()) {

      String msgXML = rs.getString(1);

      // 解析时间eg.Tue Apr 16 15:32:39 CST 2013

      Date creationDate = new Date(Long.parseLong(rs.getString(2)

      .trim()));

      OfflineMessage message;

      try {

      message = new OfflineMessage(creationDate, xmlReader.read(

      new StringReader(msgXML)).getRootElement());

      } catch (DocumentException e) {

      // Try again after removing invalid XML chars (e.g. )

      Matcher matcher = pattern.matcher(msgXML);

      if (matcher.find()) {

      msgXML = matcher.replaceAll("");

      }

      message = new OfflineMessage(creationDate, xmlReader.read(

      new StringReader(msgXML)).getRootElement());

      }

      1. // Add a delayed delivery (XEP-0203) element to the message.
      2. Element delay = message.addChildElement("delay",
      3. "urn:xmpp:delay");
      4. delay.addAttribute("from", XMPPServer.getInstance()
      5. .getServerInfo().getXMPPDomain());
      6. delay.addAttribute("stamp",
      7. XMPPDateTimeFormat.format(creationDate));
      8. // Add a legacy delayed delivery (XEP-0091) element to the
      9. // message. XEP is obsolete and support should be dropped in
      10. // future.
      11. delay = message.addChildElement("x", "jabber:x:delay");
      12. delay.addAttribute("from", XMPPServer.getInstance()
      13. .getServerInfo().getXMPPDomain());
      14. delay.addAttribute("stamp",
      15. XMPPDateTimeFormat.formatOld(creationDate));
      16. messages.add(message);
      17. }
      18. // Check if the offline messages loaded should be deleted, and that
      19. // there are
      20. // messages to delete.
      21. if (delete && !messages.isEmpty()) {
      22. PreparedStatement pstmt2 = null;
      23. try {
      24. pstmt2 = con.prepareStatement(DELETE_OFFLINE);
      25. pstmt2.setString(1, username);
      26. pstmt2.executeUpdate();
      27. removeUsernameFromSizeCache(username);
      28. } catch (Exception e) {
      29. Log.error("Error deleting offline messages of username: "
      30. + username, e);
      31. } finally {
      32. DbConnectionManager.closeStatement(pstmt2);
      33. }
      34. }

      } catch (Exception e) {

      Log.error("Error retrieving offline messages of username: "

      + username, e);

      } finally {

      DbConnectionManager.closeConnection(rs, pstmt, con);

      // Return the sax reader to the pool

      if (xmlReader != null) {

      xmlReaders.add(xmlReader);

      }

      }

      return messages;

      }

    /**

    • Returns the offline message of the specified user with the given creation
    • date. The returned message will NOT be deleted from the database.
    • @param username
      1. the username of the user who's message you'd like to receive.
    • @param creationDate
      1. the date when the offline message was stored in the database.
    • @return the offline message of the specified user with the given creation
      1. stamp.

    */

    public OfflineMessage getMessage(String username, Date creationDate) {

    OfflineMessage message = null;

    Connection con = null;

    PreparedStatement pstmt = null;

    ResultSet rs = null;

    SAXReader xmlReader = null;

    try {

    // Get a sax reader from the pool

    xmlReader = xmlReaders.take();

    con = DbConnectionManager.getConnection();

    pstmt = con.prepareStatement(LOAD_OFFLINE_MESSAGE);

    pstmt.setString(1, username);

    pstmt.setString(2, StringUtils.dateToMillis(creationDate));

    rs = pstmt.executeQuery();

    while (rs.next()) {

    String msgXML = rs.getString(1);

    message = new OfflineMessage(creationDate, xmlReader.read(

    new StringReader(msgXML)).getRootElement());

    // Add a delayed delivery (XEP-0203) element to the message.

    Element delay = message.addChildElement("delay",

    "urn:xmpp:delay");

    delay.addAttribute("from", XMPPServer.getInstance()

    .getServerInfo().getXMPPDomain());

    delay.addAttribute("stamp",

    XMPPDateTimeFormat.format(creationDate));

    // Add a legacy delayed delivery (XEP-0091) element to the

    // message. XEP is obsolete and support should be dropped in

    // future.

    delay = message.addChildElement("x", "jabber❌delay");

    delay.addAttribute("from", XMPPServer.getInstance()

    .getServerInfo().getXMPPDomain());

    delay.addAttribute("stamp",

    XMPPDateTimeFormat.formatOld(creationDate));

    }

    } catch (Exception e) {

    Log.error("Error retrieving offline messages of username: "

    + username + " creationDate: " + creationDate, e);

    } finally {

    // Return the sax reader to the pool

    if (xmlReader != null) {

    xmlReaders.add(xmlReader);

    }

    DbConnectionManager.closeConnection(rs, pstmt, con);

    }

    return message;

    }

    /**

    • Deletes all offline messages in the store for a user.
    • @param username
      1. the username of the user who's messages are going to be
      1. deleted.

    */

    public void deleteMessages(String username) {

    Connection con = null;

    PreparedStatement pstmt = null;

    try {

    con = DbConnectionManager.getConnection();

    pstmt = con.prepareStatement(DELETE_OFFLINE);

    pstmt.setString(1, username);

    pstmt.executeUpdate();

    1. removeUsernameFromSizeCache(username);
    2. } catch (Exception e) {
    3. Log.error("Error deleting offline messages of username: "
    4. + username, e);
    5. } finally {
    6. DbConnectionManager.closeConnection(pstmt, con);
    7. }

    }

    private void removeUsernameFromSizeCache(String username) {

    // Update the cached size if it exists.

    if (sizeCache.containsKey(username)) {

    sizeCache.remove(username);

    }

    }

    /**

    • Deletes the specified offline message in the store for a user. The way to
    • identify the message to delete is based on the creationDate and username.
    • @param username
      1. the username of the user who's message is going to be deleted.
    • @param creationDate
      1. the date when the offline message was stored in the database.

    */

    public void deleteMessage(String username, Date creationDate) {

    Connection con = null;

    PreparedStatement pstmt = null;

    try {

    con = DbConnectionManager.getConnection();

    pstmt = con.prepareStatement(DELETE_OFFLINE_MESSAGE);

    pstmt.setString(1, username);

    pstmt.setString(2, StringUtils.dateToMillis(creationDate));

    pstmt.executeUpdate();

    1. // Force a refresh for next call to getSize(username),
    2. // it's easier than loading the message to be deleted just
    3. // to update the cache.
    4. removeUsernameFromSizeCache(username);
    5. } catch (Exception e) {
    6. Log.error("Error deleting offline messages of username: "
    7. + username + " creationDate: " + creationDate, e);
    8. } finally {
    9. DbConnectionManager.closeConnection(pstmt, con);
    10. }

    }

    /**

    • Returns the approximate size (in bytes) of the XML messages stored for a
    • particular user.
    • @param username
      1. the username of the user.
    • @return the approximate size of stored messages (in bytes).

      */

      public int getSize(String username) {

      // See if the size is cached.

      if (sizeCache.containsKey(username)) {

      return sizeCache.get(username);

      }

      int size = 0;

      Connection con = null;

      PreparedStatement pstmt = null;

      ResultSet rs = null;

      try {

      con = DbConnectionManager.getConnection();

      pstmt = con.prepareStatement(SELECT_SIZE_OFFLINE);

      pstmt.setString(1, username);

      rs = pstmt.executeQuery();

      if (rs.next()) {

      size = rs.getInt(1);

      }

      // Add the value to cache.

      sizeCache.put(username, size);

      } catch (Exception e) {

      Log.error(LocaleUtils.getLocalizedString("admin.error"), e);

      } finally {

      DbConnectionManager.closeConnection(rs, pstmt, con);

      }

      return size;

      }

    /**

    • Returns the approximate size (in bytes) of the XML messages stored for
    • all users.
    • @return the approximate size of all stored messages (in bytes).

      */

      public int getSize() {

      int size = 0;

      Connection con = null;

      PreparedStatement pstmt = null;

      ResultSet rs = null;

      try {

      con = DbConnectionManager.getConnection();

      pstmt = con.prepareStatement(SELECT_SIZE_ALL_OFFLINE);

      rs = pstmt.executeQuery();

      if (rs.next()) {

      size = rs.getInt(1);

      }

      } catch (Exception e) {

      Log.error(LocaleUtils.getLocalizedString("admin.error"), e);

      } finally {

      DbConnectionManager.closeConnection(rs, pstmt, con);

      }

      return size;

      }

    public void userCreated(User user, Map params) {

    // Do nothing

    }

    public void userDeleting(User user, Map params) {

    // Delete all offline messages of the user

    deleteMessages(user.getUsername());

    }

    public void userModified(User user, Map params) {

    // Do nothing

    }

    @Override

    public void start() throws IllegalStateException {

    super.start();

    // Initialize the pool of sax readers

    for (int i = 0; i < POOL_SIZE; i++) {

    SAXReader xmlReader = new SAXReader();

    xmlReader.setEncoding("UTF-8");

    xmlReaders.add(xmlReader);

    }

    // Add this module as a user event listener so we can delete

    // all offline messages when a user is deleted

    UserEventDispatcher.addListener(this);

    }

    @Override

    public void stop() {

    super.stop();

    // Clean up the pool of sax readers

    xmlReaders.clear();

    // Remove this module as a user event listener

    UserEventDispatcher.removeListener(this);

    }

    }

源码详解openfire保存消息记录_修改服务端方式的更多相关文章

  1. RocketMQ源码详解 | Producer篇 · 其二:消息组成、发送链路

    概述 在上一节 RocketMQ源码详解 | Producer篇 · 其一:Start,然后 Send 一条消息 中,我们了解了 Producer 在发送消息的流程.这次我们再来具体下看消息的构成与其 ...

  2. RocketMQ源码详解 | Consumer篇 · 其一:消息的 Pull 和 Push

    概述 当消息被存储后,消费者就会将其消费. 这句话简要的概述了一条消息的最总去向,也引出了本文将讨论的问题: 消息什么时候才对被消费者可见? 是在 page cache 中吗?还是在落盘后?还是像 K ...

  3. RocketMQ源码详解 | Broker篇 · 其四:事务消息、批量消息、延迟消息

    概述 在上文中,我们讨论了消费者对于消息拉取的实现,对于 RocketMQ 这个黑盒的心脏部分,我们顺着消息的发送流程已经将其剖析了大半部分.本章我们不妨乘胜追击,接着讨论各种不同的消息的原理与实现. ...

  4. 源码详解系列(七) ------ 全面讲解logback的使用和源码

    什么是logback logback 用于日志记录,可以将日志输出到控制台.文件.数据库和邮件等,相比其它所有的日志系统,logback 更快并且更小,包含了许多独特并且有用的特性. logback ...

  5. Activiti架构分析及源码详解

    目录 Activiti架构分析及源码详解 引言 一.Activiti设计解析-架构&领域模型 1.1 架构 1.2 领域模型 二.Activiti设计解析-PVM执行树 2.1 核心理念 2. ...

  6. 源码详解系列(六) ------ 全面讲解druid的使用和源码

    简介 druid是用于创建和管理连接,利用"池"的方式复用连接减少资源开销,和其他数据源一样,也具有连接数控制.连接可靠性测试.连接泄露控制.缓存语句等功能,另外,druid还扩展 ...

  7. RocketMQ源码详解 | Broker篇 · 其三:CommitLog、索引、消费队列

    概述 上一章中,已经介绍了 Broker 的文件系统的各个层次与部分细节,本章将继续了解在逻辑存储层的三个文件 CommitLog.IndexFile.ConsumerQueue 的一些细节.文章最后 ...

  8. RocketMQ源码详解 | Broker篇 · 其五:高可用之主从架构

    概述 对于一个消息中间件来讲,高可用功能是极其重要的,RocketMQ 当然也具有其对应的高可用方案. 在 RocketMQ 中,有主从架构和 Dledger 两种高可用方案: 第一种通过主 Brok ...

  9. Spark Streaming揭秘 Day25 StreamingContext和JobScheduler启动源码详解

    Spark Streaming揭秘 Day25 StreamingContext和JobScheduler启动源码详解 今天主要理一下StreamingContext的启动过程,其中最为重要的就是Jo ...

随机推荐

  1. vs2010快捷键

    vs的快捷键包含部分代码的自动生成 VS2010 快捷键 全屏:Shift+Alt+Enter 注释选定内容:Ctrl+E+C/Crtr+E+U 代码格式化:ctrl+E+F VS2008 使用小技巧 ...

  2. 【转】FastCgi与PHP-fpm关系

    刚开始对这个问题我也挺纠结的,看了<HTTP权威指南>后,感觉清晰了不少. 首先,CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的,方便CGI程序的编写者. ...

  3. Windows Azure Traffic Manager (5) Traffic Manager Overview

    <Windows Azure Platform 系列文章目录> 笔者默默地看了一下之前写的Traffic Manager内容,已经差不多是3年前的文章了.现在Azure Traffic M ...

  4. 九、SDP

    1.      SDP 1.1       服务概述 SDP, Service Discovery Protocol,服务发现协议. 1.1.1    概念 SDP提供了一种用于发现服务及这些可用服务 ...

  5. C# 视频流操作

    发送视频流 void SendVideoBuffer(object bufferIn) { try { TcpClient tcp = ); NetworkStream ns = tcp.GetStr ...

  6. C# 3DES加密

    最近一个项目中,因为服务端是用的java开发的,客户端是用的C#,由于通信部分采用到了3DES加密,所以做个记录,以备以后需要的时候直接用. 这是对方(java)的加密算法,和网上流传的代码也差不多( ...

  7. ASP.NET MVC显示HTML字符串

    一些html经HtmlEncode后,如“<span>测试数据</span>”.现需要把这些内容正常显示于asp.net mvc的视图内. 举个例子来解决与说明,先创建一个mo ...

  8. 在WCF数据访问中使用缓存提高Winform字段中文显示速度

    在我们开发基于WCF访问方式的Winform程序的时候,一般情况下需要对界面显示的字段进行中文显示的解析.如果是硬编码进行中文显示,那么除了不方便调整及代码臃肿外,性能上没有什么问题,但是不建议这样处 ...

  9. WinForm 多窗体操作

    1多窗体操作:确定哪个是主窗体 通过窗体进入其他窗体 代码如下 Form2 f2 = new Form2();//f2窗体实例化出来 f2.Show();//进入f2窗体 this.Hide();// ...

  10. javascript的一些bug

    JavaScript是如今最受欢迎的编程语言之一,但受欢迎同时就是该语言自身的各种特性带来的副作用,无论该语言多美妙,每天还是有成千上万的程序员弄出一堆bug.先不要嘲笑别人,或许你也是其中之一. 给 ...