课程设计。

利用了Socket搭建了一个服务端和客户端,两个端之间可以通信。

使用了数据库,密码学,TCP/UDP通信协议,文件读写流等方面的技术

只支持一对多,文件传输,聊天

一个用来润色的登录界面,其实没有也行。

主界面

点击启动按钮后,会自动默认为服务端。且启动按钮会变成红色

如果点击连接了就自动默认为是客户端,即可跟服务端进行通信。

两个端之间可以进行通信和传输文件。

底下两个按钮就是可以保存当前的聊天记录,根据服务端和客户端可以区分聊天记录,下次可以读取记录进行继续聊天。(很鸡肋,可有可无,因为也没有具体到给用户做判断。)

代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;
using STalk;namespace AllClient
{public partial class Form1 : Form{public Socket ClientSocket { get; set; }//自定义字段List<Socket> ClientSocketList = new List<Socket>();//服务端代理list集合public Dictionary<string, string> dic = new Dictionary<string, string>();//用户名字典bool IsStar = false;//是否启动bool IsConnet = false;//是否连接bool SeverConnet = false;//服务端是否已经添加过字典public Form1(){InitializeComponent();CurrentName.Text = SUserName.Username;CheckForIllegalCrossThreadCalls = false;}private void Bodytxt_KeyPress(object sender, KeyPressEventArgs e){e.Handled = true;//使用户输入失效}private void BtnStar_Click(object sender, EventArgs e)//启动键{if (IsStar)//检测用户是否已启动{MessageBox.Show("已启动,请勿重复启动", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);}else{this.BtnStar.BackColor = Color.FromArgb(155, 51, 76);//UI颜色改变this.panel3.BackColor = Color.FromArgb(105, 51, 76);//全部可显示BodyTxt.Visible = true;MsgTxt.Visible = true;BtnSendMsg.Visible = true;button1.Visible = true;label1.Visible = true;listBox1.Visible = true;Logopic.Visible = false;//logo不可见JsName.Text = "服务端";IsStar = true;//1实例化socket类,寻址方式,类型,协议。Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);//2实例化端口号IPEndPoint ip = new IPEndPoint(IPAddress.Parse(IpTxt.Text),int.Parse(PortTxt.Text));//3绑定端口号try{socket.Bind(ip);//4开启监听socket.Listen(10);//只能处理一个,其余放在连接等待队列队列,最多只放10个,多出会返回错误//5开始接受客户端连接//WaitCallback waitCallback = new WaitCallback(this.AcceptClientConnet);//线程池的回调方法ThreadPool.QueueUserWorkItem(AcceptClientConnet, socket);//为了反复连接,使用线程池//ConnetNumber.dic.Add(IpTxt.Text, CurrentName.Text);}catch (Exception){IsStar = false;MessageBox.Show("IP和端口号已使用或者IP输入错误!", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);}}}private void BtnConnet_Click(object sender, EventArgs e)//连接键{if (IsConnet){MessageBox.Show("已连接,请勿重复连接", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);}else if (IsStar){MessageBox.Show("已作为服务端启动,不能连接", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);}else{this.BtnConnet.BackColor = Color.FromArgb(155, 51, 76);//改变UI颜色this.panel3.BackColor = Color.FromArgb(155, 151, 176);//全部可显示BodyTxt.Visible = true;MsgTxt.Visible = true;BtnSendMsg.Visible = true;button1.Visible = true;label1.Visible = true;listBox1.Visible = true;Logopic.Visible = false;//logo不可见JsName.Text = "客户端";IsStar = true;// 客户端连接服务器端//1创建socket对象Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);ClientSocket = socket;//赋值自定义字段//2连接服务器端try{IsConnet = true;socket.Connect(IPAddress.Parse(IpTxt.Text), int.Parse(PortTxt.Text));this.AppendTextToTxtLog(string.Format("连接上了服务端:{0}", ClientSocket.RemoteEndPoint.ToString()));ClientSocketList.Add(ClientSocket);//当有人连接上了就放到集合里显示SendUsername();//发送用户名//ConnetNumber.dic.Add(socket.RemoteEndPoint.ToString(), CurrentName.Text);//添加进静态字典// listBox1.Items.Add(ClientSocket.RemoteEndPoint.ToString());//添加入列表}catch (Exception ex){IsConnet = false;/*Thread.Sleep(500);BtnConnet_Click(this, e);return;*/MessageBox.Show("连接失败,请重新连接,连接失败原因是:" + ex.ToString());}//3发送消息,接收消息Thread thread = new Thread(new ParameterizedThreadStart(ReceiveSeverData));//启动线程thread.IsBackground = true;//该值指示某个线程是否为后台线程。thread.Start(ClientSocket);}}private void button1_Click(object sender, EventArgs e)//发送文件按钮{using (OpenFileDialog ofd = new OpenFileDialog())//打开文件选取框{if (ofd.ShowDialog(this) != DialogResult.OK){return;}byte[] data = File.ReadAllBytes(ofd.FileName);//获取选择的文件byte[] result = new byte[data.Length + 1];//创建一个新数组result[0] = 3;//在新数组上加上协议的头部字节,3代表是文件Buffer.BlockCopy(data, 0, result, 1, data.Length);//把原始的数据放到最终的字节数组里去,buffer是块拷贝foreach (var proxSocket in ClientSocketList){if (!proxSocket.Connected){continue;}// 把要发送的文件读取来proxSocket.Send(result, SocketFlags.None);MessageBox.Show("文件已发送,等待对方接收。", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);AppendTextToTxtLog("你向对方发送了文件。");}}}public void ReceiveSeverData(object socket)//接收服务端消息的方法{var ProxSocket = socket as Socket;byte[] data = new byte[1024 * 1024];//接收消息的缓冲区while (true){int len = 0;//记录消息长度try{len = ProxSocket.Receive(data, 0, data.Length, SocketFlags.None);}catch (Exception){//异常退出AppendTextToTxtLog(string.Format("服务端:{0}异常断开",ProxSocket.RemoteEndPoint.ToString()));StopConnet();return;}if (len <= 0){//如果小于0,证明无连接,客户端正常退出AppendTextToTxtLog(string.Format("服务端:{0}断开连接了。",ProxSocket.RemoteEndPoint.ToString()));StopConnet();return;//让方法结束,终结当前接收客户端数据的异步线程}//把接收到的消息放到了文本框上去//接受的数据第一个字节如果是1就是字符串,3就是文件if (data[0] == 1)//字符串{string str = Encoding.Default.GetString(data, 1, len - 1);//二进制数组转换成字符串AppendTextToTxtLog(string.Format("{0}:{1}",dic[ProxSocket.RemoteEndPoint.ToString()], str));//调用方法放置消息到文本框中,RemoteEndPoint获取远程终结点。}else if (data[0] == 2)//用户名添加{string str = Encoding.Default.GetString(data, 1, len - 1) + "  [服务端]";try{if (SeverConnet == false){dic.Add(ProxSocket.RemoteEndPoint.ToString(), str);SeverConnet = true;//服务端已添加listBox1.Items.Add(str);}}catch{//string str2 = Encoding.Default.GetString(data, 1, len - 1);//listBox1.Items.Add(str2);}}else if (data[0] == 3)//文件{DialogResult r = MessageBox.Show("对方向你发送了文件,是否接收?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);if (r == DialogResult.OK){try{ProcessRecieveFile(data, len);AppendTextToTxtLog(string.Format("服务器端:{0}向你发送了文件。",ProxSocket.RemoteEndPoint.ToString()));MessageBox.Show("保存成功!", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);}catch{MessageBox.Show("保存失败!", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);}}}}}public void ReceiveData(object socket)//接收客户端消息的方法{var ProxSocket = socket as Socket;byte[] data = new byte[1024 * 1024];//接收消息的缓冲区while (true){int len = 0;//记录消息长度try{len = ProxSocket.Receive(data, 0, data.Length, SocketFlags.None);}catch (Exception){//异常退出AppendTextToTxtLog(string.Format("客户端:{0}异常断开",ProxSocket.RemoteEndPoint.ToString()));ClientSocketList.Remove(ProxSocket);StopConnet(ProxSocket);return;}if (len <= 0){//如果小于0,证明无连接,服务端正常退出AppendTextToTxtLog(string.Format("客户端:{0}断开连接了。",ProxSocket.RemoteEndPoint.ToString()));ClientSocketList.Remove(ProxSocket);StopConnet(ProxSocket);return;//让方法结束,终结当前接收服务端数据的异步线程}//把接收到的消息放到了文本框上去if (data[0] == 1)//字符串{string str = Encoding.Default.GetString(data, 1, len - 1);//二进制数组转换成字符串AppendTextToTxtLog(string.Format("{0}:{1}",dic[ProxSocket.RemoteEndPoint.ToString()], str));//调用方法放置消息到文本框中,RemoteEndPoint获取远程终结点。//if(dic[ProxSocket.RemoteEndPoint.ToString()])//foreach (var ProxSocket in ClientSocketList)//{//    if (ProxSocket.Connected)//    {//        byte[] data = Encoding.Default.GetBytes(MsgTxt.Text);//        byte[] result = new byte[data.Length + 1];//创建新数组//        result[0] = 1;//定义协议头部为1,1为字符串发送//        Buffer.BlockCopy(data, 0, result, 1, data.Length);//把原始的数据放到最终的字节数组里去,buffer是块拷贝//        ProxSocket.Send(result, 0, result.Length, SocketFlags.None);//        AppendTextToTxtLog("你说:" + MsgTxt.Text);//调用方法放置消息到文本框中//        MsgTxt.Text = "";//    }//}}else if (data[0] == 2)//用户名添加{string str = Encoding.Default.GetString(data, 1, len - 1);dic.Add(ProxSocket.RemoteEndPoint.ToString(), str);listBox1.Items.Add(str);}else if (data[0] == 3)//文件{DialogResult r = MessageBox.Show("对方向你发送了文件,是否接收?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);if (r == DialogResult.OK){ProcessRecieveFile(data, len);AppendTextToTxtLog(string.Format("服务器端:{0}向你发送了文件。",ProxSocket.RemoteEndPoint.ToString()));}}}}public void AcceptClientConnet(object socket)//连接方法{var serverSocket = socket as Socket;//强制转换this.AppendTextToTxtLog("服务器开始接收客户端连接。");while (true){var ProxSocket = serverSocket.Accept();this.AppendTextToTxtLog(string.Format("客户端:{0}连接上了", ProxSocket.RemoteEndPoint.ToString()));ClientSocketList.Add(ProxSocket);//当有人连接上了就放到集合里显示SendUsername();//listBox1.Items.Add(ProxSocket.RemoteEndPoint.ToString());//添加入列表//listBox1.Items.Add(UserCurrentName.Text);//添加入列表//不停地接收当前链接客户端发送来的消息,使用线程池//WaitCallback waitCallback = new WaitCallback(this.ReceiveData);//线程池需要使用方法做变量,定义一个回调,使用自己写的方法ThreadPool.QueueUserWorkItem(ReceiveData, ProxSocket);//为了反复连接,使用线程池}}public void AppendTextToTxtLog(string txt)//往文本框添加消息的方法{if (BodyTxt.InvokeRequired)//如果控件的 true 是在与调用线程不同的线程上创建的//(说明您必须通过 Invoke 方法对控件进行调用),则为//Handle;否则为 false{//可以使用 Action<T> 委托将方法作为参数传递//,而无需显式声明自定义委托。 BodyTxt.Invoke(new Action<string>(s =>{this.BodyTxt.Text = string.Format("{0}\r\n{1}", s, BodyTxt.Text);//格式化字符串}), txt);}else{this.BodyTxt.Text = string.Format("{0}\r\n{1}", txt, BodyTxt.Text);}}private void StopConnet()//关闭连接{try{if (ClientSocket.Connected){ClientSocket.Shutdown(SocketShutdown.Both);//禁用某 Socket 上的发送和接收。ClientSocket.Close(100);}}catch (Exception){}}private void StopConnet(Socket proxsocket)//关闭连接{try{if (proxsocket.Connected){proxsocket.Shutdown(SocketShutdown.Both);//禁用某 Socket 上的发送和接收。proxsocket.Close(100);}}catch (Exception){}}public void ProcessRecieveFile(byte[] data, int len)//文件处理{using (SaveFileDialog sfd = new SaveFileDialog()){sfd.DefaultExt = "";sfd.Filter = "文本文件(*.txt)|*.txt|图像文件(*.jpg)" +"|*.jpg|word文件(*.doc)|*.doc|视频文件(*.mp4)" +"|*.mp4|所有文件(*.*)|*.*";if (sfd.ShowDialog(this) != DialogResult.OK){return;}byte[] fileData = new byte[len - 1];Buffer.BlockCopy(data, 1, fileData, 0, len - 1);File.WriteAllBytes(sfd.FileName, fileData);}}private void BtnSendMsg_Click(object sender, EventArgs e)//发送消息{try{if (IsStar){foreach (var ProxSocket in ClientSocketList){if (ProxSocket.Connected){byte[] data = Encoding.Default.GetBytes(MsgTxt.Text);byte[] result = new byte[data.Length + 1];//创建新数组result[0] = 1;//定义协议头部为1,1为字符串发送Buffer.BlockCopy(data, 0, result, 1, data.Length);//把原始的数据放到最终的字节数组里去,buffer是块拷贝ProxSocket.Send(result, 0, result.Length, SocketFlags.None);AppendTextToTxtLog("你说:" + MsgTxt.Text);//调用方法放置消息到文本框中MsgTxt.Text = "";}}}else if (IsConnet){if (ClientSocket.Connected){byte[] data = Encoding.Default.GetBytes(MsgTxt.Text);byte[] res = new byte[data.Length + 1];res[0] = 1;Buffer.BlockCopy(data, 0, res, 1, data.Length);ClientSocket.Send(res, 0, res.Length, SocketFlags.None);AppendTextToTxtLog("你说:" + MsgTxt.Text);//调用方法放置消息到文本框中MsgTxt.Text = "";/*foreach (var ProxSocket in ClientSocketList){if (ProxSocket.Connected){byte[] data = Encoding.Default.GetBytes(MsgTxt.Text);byte[] result = new byte[data.Length + 1];//创建新数组result[0] = 1;//定义协议头部为1,1为字符串发送Buffer.BlockCopy(data, 0, result, 1, data.Length);//把原始的数据放到最终的字节数组里去,buffer是块拷贝ClientSocket.Send(result, 0, result.Length, SocketFlags.None);AppendTextToTxtLog("你说:" + MsgTxt.Text);//调用方法放置消息到文本框中MsgTxt.Text = "";}}*/}}}catch (Exception ex){MessageBox.Show("发送失败,请重新连接,连接失败原因是:" + ex.ToString());}}private void MsgTxt_KeyDown(object sender, KeyEventArgs e)//回车键发送消息{if (e.KeyCode == Keys.Enter){try{if (IsStar){foreach (var ProxSocket in ClientSocketList){if (ProxSocket.Connected){byte[] data = Encoding.Default.GetBytes(MsgTxt.Text);byte[] result = new byte[data.Length + 1];//创建新数组result[0] = 1;//定义协议头部为1,1为字符串发送Buffer.BlockCopy(data, 0, result, 1, data.Length);//把原始的数据放到最终的字节数组里去,buffer是块拷贝ProxSocket.Send(result, 0, result.Length, SocketFlags.None);AppendTextToTxtLog("你说:" + MsgTxt.Text);//调用方法放置消息到文本框中MsgTxt.Text = "";}}}else if (IsConnet){if (ClientSocket.Connected){byte[] data = Encoding.Default.GetBytes(MsgTxt.Text);byte[] res = new byte[data.Length + 1];res[0] = 1;Buffer.BlockCopy(data, 0, res, 1, data.Length);ClientSocket.Send(res, 0, res.Length, SocketFlags.None);AppendTextToTxtLog("你说:" + MsgTxt.Text);//调用方法放置消息到文本框中MsgTxt.Text = "";}}}catch (Exception ex){MessageBox.Show("发送失败,请重新连接,连接失败原因是:" + ex.ToString());}}}public void SendUsername()//发送用户名{string r = CurrentName.Text.Trim();if (IsConnet){byte[] data = Encoding.Default.GetBytes(r);byte[] res = new byte[data.Length + 1];res[0] = 2;Buffer.BlockCopy(data, 0, res, 1, data.Length);ClientSocket.Send(res);}else if (IsStar){foreach (var ProxSocket in ClientSocketList){if (ProxSocket.Connected){byte[] data = Encoding.Default.GetBytes(r);byte[] res = new byte[data.Length + 1];res[0] = 2;Buffer.BlockCopy(data, 0, res, 1, data.Length);ProxSocket.Send(res);}}}}/*public void SendMessage(byte[] buffer)//发送消息给所有用户{//获得用户在下拉框的IP地址var task1 = new Task(() =>{for (int i = 0; i < ClientSocketList.Count; i++){string ip = ClientSocketList[i].ToString();//dic[ip].Send(buffer.ToArray());}});task1.Start();}*/private void button2_Click(object sender, EventArgs e)//修改昵称{if (NameTxt.Text == ""){MessageBox.Show("昵称不能为空!", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);}else{CurrentName.Text = NameTxt.Text.Trim();}}private void NameTxt_KeyDown(object sender, KeyEventArgs e)//回车修改昵称{if (e.KeyCode == Keys.Enter){if (NameTxt.Text == ""){MessageBox.Show("昵称不能为空!", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);}else{CurrentName.Text = NameTxt.Text.Trim();}}}private void SaveChat_Click(object sender, EventArgs e)//保存聊天记录{if (IsConnet == false && IsStar == false){MessageBox.Show("请启动或连接后在进行保存");}else{if (IsStar == true){Chat com = new Chat{hao = 1,Smalltalk = BodyTxt.Text};SaveFileDialog save = new SaveFileDialog();save.Title = "请选择保存路径";save.InitialDirectory = @"C:";save.Filter = "xml文件|*.xml|所有文件|*.*";save.ShowDialog();if (save.ShowDialog(this) != DialogResult.OK){return;}string filename = save.FileName;StreamWriter sw = new StreamWriter(filename);XmlSerializer serializer = new XmlSerializer(typeof(Chat));serializer.Serialize(sw, com);sw.Close();}if (IsConnet == true){Chat com = new Chat{hao = 2,Smalltalk = BodyTxt.Text};SaveFileDialog save = new SaveFileDialog();save.Title = "请选择保存路径";save.InitialDirectory = @"C:";save.Filter = "xml文件|*.xml|所有文件|*.*";save.ShowDialog();if (save.ShowDialog(this) != DialogResult.OK){return;}string filename = save.FileName;StreamWriter sw = new StreamWriter(filename);XmlSerializer serializer = new XmlSerializer(typeof(Chat));serializer.Serialize(sw, com);sw.Close();}}/*     private void BtnSendImg_Click(object sender, EventArgs e)//发送图片{using (OpenFileDialog ofd = new OpenFileDialog())//打开文件选取框{if (ofd.ShowDialog(this) != DialogResult.OK){return;}byte[] data = File.ReadAllBytes(ofd.FileName);byte[] result = new byte[data.Length + 1];result[0] = 4;//4代表图片Buffer.BlockCopy(data, 0, result, 1, data.Length);foreach (var proxSocket in ClientSocketList){if (!proxSocket.Connected){continue;}// 把要发送的文件读取来//proxSocket.Send(result, SocketFlags.None);try{string str = Encoding.ASCII.GetString(data);this.BodyTxt.Rtf = str;}catch(Exception ex){MessageBox.Show(ex.ToString());}}}*/}private void LoadChat_Click(object sender, EventArgs e){OpenFileDialog ofd = new OpenFileDialog();ofd.Title = "请选择您所读取的聊天记录文件";ofd.InitialDirectory = @"C:";ofd.Multiselect = true;ofd.Filter = "xml文件|*.xml|所有文件|*.*";ofd.ShowDialog();if (ofd.ShowDialog(this) != DialogResult.OK){return;}string filename = ofd.FileName;//FileStream fs = File.Open("1234.xml", FileMode.Open);StreamReader reader = new StreamReader(filename, Encoding.UTF8);XmlSerializer serializer = new XmlSerializer(typeof(Chat));Chat com2 = (Chat)serializer.Deserialize(reader);if (IsStar == true){if (com2.hao == 1){BodyTxt.Text = com2.Smalltalk;}else{MessageBox.Show("不能读取客户端聊天记录或其他与该程序无关的xml文件!!!!!");}}if (IsConnet == true){if (com2.hao == 2){BodyTxt.Text = com2.Smalltalk;}else{MessageBox.Show("不能读取服务端聊天记录或其他与该程序无关的xml文件!!!!!");}}}}
}

当时还没有三层架构和重构代码的意识,代码全部挤在控件页了。

其实只要挂个阿里云,把IP地址和端口改一下,也可以实现内网穿透了。

虽然很稚嫩,但是是当时的心血之作,那就放上来博客了。

C#基于Socket的局域网即时通信和传输文件程序相关推荐

  1. 基于P2P的局域网即时通信应用

    前言 这是一个使用java语言开发的基于P2P的局域网即时通信Android应用,界面是高仿微信的聊天界面,在里面你将会学到java多线程并发编程.Socket编程.UDP广播.TCP连接等. 项目地 ...

  2. C语言 linux环境基于socket的简易即时通信程序

    转载请注明出处:http://www.cnblogs.com/kevince/p/3891033.html      --By Kevince 最近在看linux网络编程相关,现学现卖,就写了一个简易 ...

  3. 基于Qt的局域网即时通信系统设计与实现(提供各种版本的源代码)

    我创建了一个QQ群,有问题的话,可以直接加群:530240681. github上项目的链接:https://github.com/siyueshiqi/LAN_IM 本系统主要实现了注册登录.好友管 ...

  4. BIO、NIO、AIO 详解和基于BIO模式下即时通信

    第一章 BIO.NIO.AIO课程介绍 身边同学写的,没发布出来,我算是转载 1.1 课程说明 ​ 在Java的软件设计开发中,通信架构是不可避免的,我们在进行不同系统或者不同进程之间的数据交互,或者 ...

  5. Android基于UDP的局域网聊天通信

    代码地址如下: http://www.demodashi.com/demo/12057.html 记得把这几点描述好咯:代码实现过程 + 项目文件结构截图 + 演示效果 1. 开发环境 1.1 开发工 ...

  6. 基于Socket的网络即时通信系统

    摘 要 网络通信在当今信息社会中起着不可或缺的作用,人们可以利用网络通信技术进行即时的信息交流.例如,人们可以通过Internet搜索所要的信息,通过网上通信工具聊天,交流信息,上网购物等等. 本课题 ...

  7. python socket模块实现udp通信_Python基于socket模块实现UDP通信功能示例

    Python基于socket模块实现UDP通信功能示例 本文实例讲述了Python基于socket模块实现UDP通信功能.分享给大家供大家参考,具体如下: 一 代码 1.接收端 import sock ...

  8. Ricochet —— 基于 Tor 的加密即时通信工具

    Ricochet 是一个基于 Tor 的加密即时通信工具 Ricochet 是个与众不同的实时通信,不相信你的验证,你的联系列表和你的通信. 无需暴露你的认证(IP 地址)给任何人就可以进行聊天 没有 ...

  9. 【Java】GUI界面聊天小程序(基于Socket的客户端服务端通信)

    基于Socket的客户端服务端通信--Java GUI界面小程序 Socket概念及其通信过程: Socket是TCP/IP中的基本概念,它负责将TCP/IP包发送到指定的IP地址.也可以看成是在两个 ...

  10. 基于Socket的游戏服务器通信框架的设计与实现

    博客地址:blog.liujunliang.com.cn 开发工具:VS2017.Unity2017 本文介绍使用Socket/TCP来开发客户端与服务器端通信框架 博主使用过PhotonServer ...

最新文章

  1. iOS从零开始学习直播之音频2.后台播放和在线播放
  2. luogu4677山区建小学题解--区间DP
  3. 【深度学习】2个经典的练手CNN源码与MNIST数据集测试结果
  4. php microtime true输出说明,php使用microtime(true)查看代码执行时间
  5. oracle 删除行记录,使用实体框架从oracle数据库中删除记录
  6. centos6.5升级glibc-2.18
  7. 电压电流测量模块在matlab,MATLAB仿真时用simulink的RMS模块测量电压有效值,总提示如下警告,怎么破,跪求?...
  8. ppt矩形里面的图片怎么放大缩小_PPT5题目要求-矩形放大缩小
  9. 建设银行安徽分行副行长王文兵:金融科技赋能银行数字化转型
  10. Python4班平均成绩统计_空中交通管理学院2017级学生 20182019学年第一学期成绩分析报告...
  11. 从零开始学前端 - 3. HTML 常用标签_2
  12. thinkphp6+layui BBS社区论坛系统源码分享,支持适配移动端附截图
  13. 【案例】泰康集团——泰生活APP A/B测试平台场景应用
  14. 音视频开发-SRS 4.0流媒体服务器系列
  15. 2022年12月招聘、内推最新职位
  16. RGB及sRGB与XYZ坐标转换
  17. WPS画报的电脑壁纸怎么下载
  18. 『MongoDB』快速安装MongoDB运行环境
  19. 怎样找回e盘删除的文件夹?分享三种恢复方法
  20. 考研英语 - word-list-50

热门文章

  1. 华为eNSP和思科PNET如何正确调用抓包软件
  2. 配置PLSQL连接ORACLE数据库
  3. 临床数据库挖掘系列3-手把手教你使用R语言对seer数据库清洗
  4. 2017年 Python工程师面试经历分享(七家)
  5. 创建自己的个人网站(一)
  6. 绕x,y轴旋转曲面面积公式推导
  7. 前端必备:六款CSS工具让代码充满魅力
  8. 穷人和富人的距离0.05厘米
  9. 重新认识Git——抽丝剥茧说Git
  10. QT运行时的Debug、Release、Profile选项区别