分享WCF聊天程序--WCFChat

无意中在一个国外的站点下到了一个利用WCF实现聊天的程序,作者是:Nikola Paljetak。研究了一下,自己做了测试和部分修改,感觉还不错,分享给大家。
先来看下运行效果:
开启服务:

客户端程序:


程序分为客户端和服务器端:
------------服务器端:

IChatService.cs:

Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Collections;

namespace WCFChatService
{
    
// SessionMode.Required  允许Session会话。双工协定时的回调协定类型为IChatCallback接口
    [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IChatCallback))]
    
public interface IChatService
    {
        [OperationContract(IsOneWay 
= false, IsInitiating = true, IsTerminating = false)]//----->IsOneWay = false等待服务器完成对方法处理;IsInitiating = true启动Session会话,IsTerminating = false 设置服务器发送回复后不关闭会话
        string[] Join(string name);//用户加入

        [OperationContract(IsOneWay 
= true, IsInitiating = false, IsTerminating = false)]
        
void Say(string msg);//群聊信息

        [OperationContract(IsOneWay 
= true, IsInitiating = false, IsTerminating = false)]
        
void Whisper(string to, string msg);//私聊信息

        [OperationContract(IsOneWay 
= true, IsInitiating = false, IsTerminating = true)]
        
void Leave();//用户加入
    }
    
/// <summary>
    
/// 双向通信的回调接口
    
/// </summary>
    interface IChatCallback
    {
        [OperationContract(IsOneWay 
= true)]
        
void Receive(string senderName, string message);

        [OperationContract(IsOneWay 
= true)]
        
void ReceiveWhisper(string senderName, string message);

        [OperationContract(IsOneWay 
= true)]
        
void UserEnter(string name);

        [OperationContract(IsOneWay 
= true)]
        
void UserLeave(string name);
    }

    
/// <summary>
    
/// 设定消息的类型
    
/// </summary>
    public enum MessageType { Receive, UserEnter, UserLeave, ReceiveWhisper };
    
/// <summary>
    
/// 定义一个本例的事件消息类. 创建包含有关事件的其他有用的信息的变量,只要派生自EventArgs即可。
    
/// </summary>
    public class ChatEventArgs : EventArgs
    {
        
public MessageType msgType;
        
public string name;
        
public string message;
    }
}

ChatService.cs

Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace WCFChatService
{
    
// InstanceContextMode.PerSession 服务器为每个客户会话创建一个新的上下文对象。ConcurrencyMode.Multiple 异步的多线程实例
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
    
public class ChatService : IChatService
    {
        
private static Object syncObj = new Object();////定义一个静态对象用于线程部份代码块的锁定,用于lock操作
        IChatCallback callback = null;

        
public delegate void ChatEventHandler(object sender, ChatEventArgs e);//定义用于把处理程序赋予给事件的委托。
        public static event ChatEventHandler ChatEvent;//定义事件
        static Dictionary<string, ChatEventHandler> chatters = new Dictionary<string, ChatEventHandler>();//创建一个静态Dictionary(表示键和值)集合(字典),用于记录在线成员,Dictionary<(Of <(TKey, TValue>)>) 泛型类

        
private string name;
        
private ChatEventHandler myEventHandler = null;


        
public string[] Join(string name)
        {
            
bool userAdded = false;
            myEventHandler 
= new ChatEventHandler(MyEventHandler);//将MyEventHandler方法作为参数传递给委托

            
lock (syncObj)//线程的同步性,同步访问多个线程的任何变量,利用lock(独占锁),确保数据访问的唯一性。
            {
                
if (!chatters.ContainsKey(name) && name != "" && name != null)
                {
                    
this.name = name;
                    chatters.Add(name, MyEventHandler);
                    userAdded 
= true;
                }
            }

            
if (userAdded)
            {
                callback 
= OperationContext.Current.GetCallbackChannel<IChatCallback>();//获取当前操作客户端实例的通道给IChatCallback接口的实例callback,此通道是一个定义为IChatCallback类型的泛类型,通道的类型是事先服务契约协定好的双工机制。
                ChatEventArgs e = new ChatEventArgs();//实例化事件消息类ChatEventArgs
                e.msgType = MessageType.UserEnter;
                e.name 
= name;
                BroadcastMessage(e);
                ChatEvent 
+= myEventHandler;
                
string[] list = new string[chatters.Count]; //以下代码返回当前进入聊天室成员的称列表
                lock (syncObj)
                {
                    chatters.Keys.CopyTo(list, 
0);//将字典中记录的用户信息复制到数组中返回。
                }
                
return list;
            }
            
else
            {
                
return null;
            }
        }

        
public void Say(string msg)
        {
            ChatEventArgs e 
= new ChatEventArgs();
            e.msgType 
= MessageType.Receive;
            e.name 
= this.name;
            e.message 
= msg;
            BroadcastMessage(e);
        }

        
public void Whisper(string to, string msg)
        {
            ChatEventArgs e 
= new ChatEventArgs();
            e.msgType 
= MessageType.ReceiveWhisper;
            e.name 
= this.name;
            e.message 
= msg;
            
try
            {
                ChatEventHandler chatterTo;
//创建一个临时委托实例
                lock (syncObj)
                {
                    chatterTo 
= chatters[to]; //查找成员字典中,找到要接收者的委托调用
                }
                chatterTo.BeginInvoke(
this, e, new AsyncCallback(EndAsync), null);//异步方式调用接收者的委托调用
            }
            
catch (KeyNotFoundException)
            {
            }
        }

        
public void Leave()
        {
            
if (this.name == null)
                
return;

            
lock (syncObj)
            {
                chatters.Remove(
this.name);
            }
            ChatEvent 
-= myEventHandler;
            ChatEventArgs e 
= new ChatEventArgs();
            e.msgType 
= MessageType.UserLeave;
            e.name 
= this.name;
            
this.name = null;
            BroadcastMessage(e);
        }

        
//回调,根据客户端动作通知对应客户端执行对应的操作
        private void MyEventHandler(object sender, ChatEventArgs e)
        {
            
try
            {
                
switch (e.msgType)
                {
                    
case MessageType.Receive:
                        callback.Receive(e.name, e.message);
                        
break;
                    
case MessageType.ReceiveWhisper:
                        callback.ReceiveWhisper(e.name, e.message);
                        
break;
                    
case MessageType.UserEnter:
                        callback.UserEnter(e.name);
                        
break;
                    
case MessageType.UserLeave:
                        callback.UserLeave(e.name);
                        
break;
                }
            }
            
catch
            {
                Leave();
            }
        }

        
private void BroadcastMessage(ChatEventArgs e)
        {

            ChatEventHandler temp 
= ChatEvent;

            
if (temp != null)
            {
                
//循环将在线的用户广播信息
                foreach (ChatEventHandler handler in temp.GetInvocationList())
                {
                    
//异步方式调用多路广播委托的调用列表中的ChatEventHandler 
                    handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
                }
            }
        }
        
//广播中线程调用完成的回调方法功能:清除异常多路广播委托的调用列表中异常对象(空对象)
        private void EndAsync(IAsyncResult ar)
        {
            ChatEventHandler d 
= null;

            
try
            {
                
//封装异步委托上的异步操作结果
                System.Runtime.Remoting.Messaging.AsyncResult asres = (System.Runtime.Remoting.Messaging.AsyncResult)ar;
                d 
= ((ChatEventHandler)asres.AsyncDelegate);
                d.EndInvoke(ar);
            }
            
catch
            {
                ChatEvent 
-= d;
            }
        }
    }
}

------------客户端:

Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.ServiceModel;

namespace WCFChatClient
{
    
public partial class ChatForm : Form, IChatServiceCallback
    {
        
/// <summary>
        
/// 该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。 
        
/// </summary>
        
/// <param name="hWnd">其窗口程序将接收消息的窗口的句柄</param>
        
/// <param name="msg">指定被发送的消息</param>
        
/// <param name="wParam">指定附加的消息指定信息</param>
        
/// <param name="lParam">指定附加的消息指定信息</param>
        [DllImport("user32.dll")]
        
private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
        
//当一个窗口标准垂直滚动条产生一个滚动事件时发送此消息给那个窗口,也发送给拥有它的控件
        private const int WM_VSCROLL = 0x115;
        
private const int SB_BOTTOM = 7;
        
private int lastSelectedIndex = -1;

        
private ChatServiceClient proxy;
        
private string userName;

        
private WaitForm wfDlg = new WaitForm();
        
private delegate void HandleDelegate(string[] list);
        
private delegate void HandleErrorDelegate();

        
public ChatForm()
        {
            InitializeComponent();
            ShowInterChatMenuItem(
true);
        }

        
/// <summary>
        
/// 连接服务器
        
/// </summary>
        private void InterChatMenuItem_Click(object sender, EventArgs e)
        {
            lbOnlineUsers.Items.Clear();
            LoginForm loginDlg 
= new LoginForm();
            
if (loginDlg.ShowDialog() == DialogResult.OK)
            {
                userName 
= loginDlg.txtUserName.Text;
                loginDlg.Close();
            }

            txtChatContent.Focus();
            Application.DoEvents();
            InstanceContext site 
= new InstanceContext(this);//为实现服务实例的对象进行初始化
            proxy = new ChatServiceClient(site);
            IAsyncResult iar 
= proxy.BeginJoin(userName, new AsyncCallback(OnEndJoin), null);
            wfDlg.ShowDialog();
        }

        
private void OnEndJoin(IAsyncResult iar)
        {
            
try
            {
                
string[] list = proxy.EndJoin(iar);
                HandleEndJoin(list);

            }
            
catch (Exception e)
            {
                HandleEndJoinError();
            }

        }
        
/// <summary>
        
/// 错误提示
        
/// </summary>
        private void HandleEndJoinError()
        {
            
if (wfDlg.InvokeRequired)
                wfDlg.Invoke(
new HandleErrorDelegate(HandleEndJoinError));
            
else
            {
                wfDlg.ShowError(
"无法连接聊天室!");
                ExitChatSession();
            }
        }
        
/// <summary>
        
/// 登录结束后的处理
        
/// </summary>
        
/// <param name="list"></param>
        private void HandleEndJoin(string[] list)
        {
            
if (wfDlg.InvokeRequired)
                wfDlg.Invoke(
new HandleDelegate(HandleEndJoin), new object[] { list });
            
else
            {
                wfDlg.Visible 
= false;
                ShowInterChatMenuItem(
false);
                
foreach (string name in list)
                {
                    lbOnlineUsers.Items.Add(name);
                }
                AppendText(
" 用户: " + userName + "--------登录---------" + DateTime.Now.ToString()+ Environment.NewLine);
            }
        }
        
/// <summary>
        
/// 退出聊天室
        
/// </summary>
        private void OutInterChatMenuItem_Click(object sender, EventArgs e)
        {
            ExitChatSession();
            Application.Exit();
        }
        
/// <summary>
        
/// 群聊
        
/// </summary>
        private void btnChat_Click(object sender, EventArgs e)
        {
            SayAndClear(
"", txtChatContent.Text, false);
            txtChatContent.Focus();
        }
        
/// <summary>
        
/// 发送消息
        
/// </summary>
        private void SayAndClear(string to, string msg, bool pvt)
        {
            
if (msg != "")
            {
                
try
                {
                    CommunicationState cs 
= proxy.State;
                    
//pvt 公聊还是私聊
                    if (!pvt)
                    {
                        proxy.Say(msg);
                    }
                    
else
                    {
                        proxy.Whisper(to, msg);
                    }

                    txtChatContent.Text 
= "";
                }
                
catch
                {
                    AbortProxyAndUpdateUI();
                    AppendText(
"失去连接: " + DateTime.Now.ToString() + Environment.NewLine);
                    ExitChatSession();
                }
            }
        }
        
private void txtChatContent_KeyPress(object sender, KeyPressEventArgs e)
        {
            
if (e.KeyChar == 13)
            {
                e.Handled 
= true;
                btnChat.PerformClick();
            }
        }
        
/// <summary>
        
/// 只有选择一个用户时,私聊按钮才可用
        
/// </summary>
        private void lbOnlineUsers_SelectedIndexChanged(object sender, EventArgs e)
        {
            AdjustWhisperButton();
        }
        
/// <summary>
        
/// 私聊
        
/// </summary>       
        private void btnWhisper_Click(object sender, EventArgs e)
        {
            
if (txtChatDetails.Text == "")
            {
                
return;
            }
            
object to = lbOnlineUsers.SelectedItem;
            
if (to != null)
            {
                
string receiverName = (string)to;
                AppendText(
"私下对" + receiverName + "说: " + txtChatContent.Text);//+ Environment.NewLine
                SayAndClear(receiverName, txtChatContent.Text, true);
                txtChatContent.Focus();
            }
        }
        
/// <summary>
        
/// 连接聊天室
        
/// </summary>
        private void ShowInterChatMenuItem(bool show)
        {
            InterChatMenuItem.Enabled 
= show;
            OutInterChatMenuItem.Enabled 
= this.btnChat.Enabled = !show;
        }
        
private void AppendText(string text)
        {
            txtChatDetails.Text 
+= text;
            SendMessage(txtChatDetails.Handle, WM_VSCROLL, SB_BOTTOM, 
new IntPtr(0));
        }
        
/// <summary>
        
/// 退出应用程序时,释放使用资源
        
/// </summary>
        private void ExitChatSession()
        {
            
try
            {
                proxy.Leave();
            }
            
catch { }
            
finally
            {
                AbortProxyAndUpdateUI();
            }
        }
        
/// <summary>
        
/// 释放使用资源
        
/// </summary>
        private void AbortProxyAndUpdateUI()
        {
            
if (proxy != null)
            {
                proxy.Abort();
                proxy.Close();
                proxy 
= null;
            }
            ShowInterChatMenuItem(
true);
        }
        
/// <summary>
        
/// 接收消息
        
/// </summary>
        public void Receive(string senderName, string message)
        {
            AppendText(senderName 
+ "说: " + message + Environment.NewLine);
        }
        
/// <summary>
        
/// 接收私聊消息
        
/// </summary>
        public void ReceiveWhisper(string senderName, string message)
        {
            AppendText(senderName 
+ " 私下说: " + message + Environment.NewLine);
        }
        
/// <summary>
        
/// 新用户登录
        
/// </summary>
        public void UserEnter(string name)
        {
            AppendText(
"用户 " + name + " --------登录---------" + DateTime.Now.ToString() + Environment.NewLine);
            lbOnlineUsers.Items.Add(name);
        }
        
/// <summary>
        
/// 用户离开
        
/// </summary>
        public void UserLeave(string name)
        {
            AppendText(
"用户 " + name + " --------离开---------" + DateTime.Now.ToString() + Environment.NewLine);
            lbOnlineUsers.Items.Remove(name);
            AdjustWhisperButton();
        }
        
/// <summary>
        
/// 控制私聊按钮的可用性,只有选择了用户时按钮才可用
        
/// </summary>
        private void AdjustWhisperButton()
        {
            
if (lbOnlineUsers.SelectedIndex == lastSelectedIndex)
            {
                lbOnlineUsers.SelectedIndex 
= -1;
                lastSelectedIndex 
= -1;
                btnWhisper.Enabled 
= false;
            }
            
else
            {
                btnWhisper.Enabled 
= true;
                lastSelectedIndex 
= lbOnlineUsers.SelectedIndex;
            }

            txtChatContent.Focus();
        }
        
/// <summary>
        
/// 窗体关闭时,释放使用资源
        
/// </summary>
        private void ChatForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            AbortProxyAndUpdateUI();
            Application.Exit();
        }
    }
}

代码中我做了详细的讲解,相信园友们完全可以看懂。代码中的一些使用的方法还是值得大家参考学习的。这里涉及到了WCF的使用方法,需要注意的是:如果想利用工具生成代理类,需要加上下面的代码:

Code
if (host.Description.Behaviors.Find<System.ServiceModel.Description.ServiceMetadataBehavior>() == null)
            {
                BindingElement metaElement 
= new TcpTransportBindingElement();
                CustomBinding metaBind 
= new CustomBinding(metaElement);
                host.Description.Behaviors.Add(
new System.ServiceModel.Description.ServiceMetadataBehavior());
                host.AddServiceEndpoint(
typeof(System.ServiceModel.Description.IMetadataExchange), metaBind, "MEX");
            }

否则在生成代理类的时候会报错如下的错误:

源码下载:
/Files/gaoweipeng/WCFChat.rar

转载于:https://www.cnblogs.com/soundcode/archive/2011/08/08/2131113.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/378278.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【神经网络扩展】:断点续训和参数提取

课程来源&#xff1a;人工智能实践:Tensorflow笔记2 文章目录前言断点续训主要步骤参数提取主要步骤总结前言 本讲目标:断点续训&#xff0c;存取最优模型&#xff1b;保存可训练参数至文本 断点续训主要步骤 读取模型&#xff1a; 先定义出存放模型的路径和文件名&#xff0…

小米手环6NFC安装太空人表盘

以前看我室友峰哥、班长都有手环&#xff0c;一直想买个手环&#xff0c;不舍得&#xff0c;然后今年除夕的时候降价&#xff0c;一狠心&#xff0c;入手了&#xff0c;配上除夕的打年兽活动还有看春晚京东敲鼓领的红包和这几年攒下来的京东豆豆&#xff0c;原价279的小米手环6…

为什么两层3*3卷积核效果比1层5*5卷积核效果要好?

目录1、感受野2、2层3 * 3卷积与1层5 * 5卷积3、2层3 * 3卷积与1层5 * 5卷积的计算量比较4、2层3 * 3卷积与1层5 * 5卷积的非线性比较5、2层3 * 3卷积与1层5 * 5卷积的参数量比较1、感受野 感受野&#xff1a;卷积神经网络各输出特征像素点&#xff0c;在原始图片映射区域大小。…

算法正确性和复杂度分析

算法正确性——循环不变式 算法复杂度的计算 方法一 代换法 —局部代换 这里直接对n变量进行代换 —替换成对数或者指数的情形 n 2^m —整体代换 这里直接对递推项进行代换 —替换成内部递推下标的形式 T(2^n) S(n) 方法二 递归树法 —用实例说明 —分析每一层的内容 —除了…

第十五章 Python和Web

第十五章 Python和Web 本章讨论Python Web编程的一些方面。 三个重要的主题&#xff1a;屏幕抓取、CGI和mod_python。 屏幕抓取 屏幕抓取是通过程序下载网页并从中提取信息的过程。 下载数据并对其进行分析。 从Python Job Board&#xff08;http://python.org/jobs&#x…

【数据结构基础笔记】【图】

代码参考《妙趣横生的算法.C语言实现》 文章目录前言1、图的概念2、图的存储形式1、邻接矩阵&#xff1a;2、邻接表3、代码定义邻接表3、图的创建4、深度优先搜索DFS5、广度优先搜索BFS6、实例分析前言 本章总结&#xff1a;图的概念、图的存储形式、邻接表定义、图的创建、图…

如何蹭网

引言蹭网&#xff0c;在普通人的眼里&#xff0c;是一种很高深的技术活&#xff0c;总觉得肯定很难&#xff0c;肯定很难搞。还没开始学&#xff0c;就已经败给了自己的心里&#xff0c;其实&#xff0c;蹭网太过于简单。我可以毫不夸张的说&#xff0c;只要你会windows的基本操…

android对象缓存,Android简单实现 缓存数据

前言1、每一种要缓存的数据都是有对应的versionCode&#xff0c;通过versionCode请求网络获取是否需要更新2、提前将要缓存的数据放入assets文件夹中&#xff0c;打包上线。缓存设计代码实现/*** Created by huangbo on 2017/6/19.** 主要是缓存的工具类** 缓存设计&#xff1a…

通信原理.绪论

今天刚上通信原理的第一节课&#xff0c;没有涉及过多的讲解&#xff0c;只是讲了下大概的知识框架。现记录如下&#xff1a; 目录1、基本概念消息、信息与信号2、通信系统模型1、信息源2、发送设备3、信道4、接收设备5、信宿6、模拟通信系统模型7、数字通信系统模型8、信源编…

css rgba透明_rgba()函数以及CSS中的示例

css rgba透明Introduction: 介绍&#xff1a; Functions are used regularly while we are developing a web page or website. Therefore, to be a good developer you need to master as many functions as you can. This way your coding knowledge will increase as well …

犀牛脚本:仿迅雷的增强批量下载

迅雷的批量下载满好用。但是有两点我不太中意。在这个脚本里会有所增强 1、不能设置保存的文件名。2、不能单独设置这批下载的线程限制。 使用方法 // 下载从编号001到编号020的图片&#xff0c;保存名为猫咪写真*.jpg 使用6个线程 jdlp http://bizhi.zhuoku.com/bizhi/200804/…

android 服务端 漏洞,安卓漏洞 CVE 2017-13287 复现详解-

2018年4月&#xff0c;Android安全公告公布了CVE-2017-13287漏洞。与同期披露的其他漏洞一起&#xff0c;同属于框架中Parcelable对象的写入(序列化)与读出(反序列化)的不一致所造成的漏洞。在刚看到谷歌对于漏洞给出的补丁时一头雾水&#xff0c;在这里要感谢heeeeenMS509Team…

GAP(全局平均池化层)操作

转载的文章链接&#xff1a; 为什么使用全局平均池化层&#xff1f; 关于 global average pooling https://blog.csdn.net/qq_23304241/article/details/80292859 在卷积神经网络的初期&#xff0c;卷积层通过池化层&#xff08;一般是 最大池化&#xff09;后总是要一个或n个全…

zoj1245 Triangles(DP)

/* 动态三角形&#xff1a;每次DP时考虑的是两个子三角形的高度即可 注意&#xff1a; 三角形可以是倒置的。 */ View Code 1 #include <iostream> 2 #include <cstdlib> 3 #include <cstring> 4 #include <stdio.h> 5 6 using namespace std; 7 8…

android编程从零开始,从零开始学习android开发

博主最近开通了Android栏目&#xff0c;现在正在从零开始学习android&#xff0c;遇到的所有值得分享的知识点以及遇到的问题将发布在这个博客的android栏目下。因为我有着深厚的java底子&#xff0c;所以学习起来得心应手&#xff0c;十分的简单&#xff0c;当然也只能算是入门…

CNN基本步骤以及经典卷积(LeNet、AlexNet、VGGNet、InceptionNet 和 ResNet)网络讲解以及tensorflow代码实现

课程来源&#xff1a;人工智能实践:Tensorflow笔记2 文章目录前言1、卷积神经网络的基本步骤1、卷积神经网络计算convolution2、感受野以及卷积核的选取3、全零填充Padding4、tf描述卷积层5、批标准化(BN操作)6、池化Pooling7、舍弃Dropout8、卷积神经网络搭建以及参数分析2、经…

第十九章 趣味编程

第十九章 趣味编程 本章将介绍一些通用的Python编程指南。 为何要有趣 Python有趣的地方之一就是让用户的编程效率非常高效。 极限编程是一种软件开发方法 编程柔术 python的灵活性描述原型设计Python的优点之一是让你能够快速地编写程序。要更深入地了解面临的问题&#…

【数据结构基础笔记】【顺序表】

代码参考《妙趣横生的算法.C语言实现》 文章目录前言1、创建顺序表2、顺序表插入元素3、顺序表删除元素4、顺序表实例分析1、静态2、动态5、顺序表总结前言 本章总结&#xff1a;从静态和动态分别进行顺序表的创建、插入、删除、以及实例分析 1、创建顺序表 1、静态地生成一张…

关于《加密与解密》的读后感----对dump脱壳的一点思考

偶然翻了一下手机日历&#xff0c;原来今天是夏至啊&#xff0c;时间过的真快。ISCC的比赛已经持续了2个多月了&#xff0c;我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦&#xff0c;但感觉还是很幸运的&#xff0c;能在大三的时候遇到ISCC&#xff0c;不管怎样&…

【数据结构基础笔记】【链表】

代码参考《妙趣横生的算法.C语言实现》 文章目录前言1、链表基础2、创建一个链表3、插入结点4、删除结点5、销毁链表6、实例分析前言 本章总结&#xff1a;链表的定义、创建、销毁&#xff0c;结点的插入与删除 1、链表基础 链表的物理存储结构是用一组地址任意的存储单元存储…