Socket 由浅入深,开发一个真正的通信应用
在说socket之前。我们先了解下相关的网络知识;
端口
在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序)。
例如:http 使用80端口 ftp使用21端口 smtp使用 25端口
端口用来标识计算机里的某个程序 1)公认端口:从0到1023 2)注册端口:从1024到49151 3)动态或私有端口:从49152到65535
Socket相关概念
socket的英文原义是“孔”或“插座”。作为进程通信机制,取后一种意思。通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄。(其实就是两个程序通信用的。)
socket非常类似于电话插座。以一个电话网为例。电话的通话双方相当于相互通信的2个程序,电话号码就是IP地址。任何用户在通话之前,
首先要占有一部电话机,相当于申请一个socket;同时要知道对方的号码,相当于对方有一个固定的socket。然后向对方拨号呼叫,
相当于发出连接请求。对方假如在场并空闲,拿起电话话筒,双方就可以正式通话,相当于连接成功。双方通话的过程,
是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机相当于关闭socket,撤消连接。
Socket有两种类型
流式Socket(STREAM):是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低;
数据报式Socket(DATAGRAM):是一种无连接的Socket,对应于无连接的UDP服务应用.不安全(丢失,顺序混乱,在接收端要分析重排及要求重发),但效率高.
TCP/IP协议
TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
UDP协议
UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。
应用层 (Application):应用层是个很广泛的概念,有一些基本相同的系统级 TCP/IP 应用以及应用协议,也有许多的企业商业应用和互联网应用。 解释:我们的应用程序
传输层 (Transport):传输层包括 UDP 和 TCP,UDP 几乎不对报文进行检查,而 TCP 提供传输保证。 解释;保证传输数据的正确性
网络层 (Network):网络层协议由一系列协议组成,包括 ICMP、IGMP、RIP、OSPF、IP(v4,v6) 等。 解释:保证找到目标对象,因为里面用的IP协议,ip包含一个ip地址
链路层 (Link):又称为物理数据网络接口层,负责报文传输。 解释:在物理层面上怎么去传递数据
你可以cmd打开命令窗口。输入
netstat -a
查看当前电脑监听的端口,和协议。有TCP和UDP
TCP/IP与UDP有什么区别呢?该怎么选择?
UDP可以用广播的方式。发送给每个连接的用户 而TCP是做不到的
TCP需要3次握手,每次都会发送数据包(但不是我们想要发送的数据),所以效率低 但数据是安全的。因为TCP会有一个校验和。就是在发送的时候。会把数据包和校验和一起 发送过去。当校验和和数据包不匹配则说明不安全(这个安全不是指数据会不会 别窃听,而是指数据的完整性)
UDP不需要3次握手。可以不发送校验和
web服务器用的是TCP协议
那什么时候用UDP协议。什么时候用TCP协议呢? 视频聊天用UDP。因为要保证速度?反之相反
下图显示了数据报文的格式
Socket一般应用模式(服务器端和客户端)
服务端跟客户端发送信息的时候,是通过一个应用程序 应用层发送给传输层,传输层加头部 在发送给网络层。在加头 在发送给链路层。在加帧
然后在链路层转为信号,通过ip找到电脑 链路层接收。去掉头(因为发送的时候加头了。去头是为了找到里面的数据) 网络层接收,去头 传输层接收。去头 在到应用程序,解析协议。把数据显示出来
TCP3次握手
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;SYN:同步序列编号(Synchronize SequenceNumbers)。 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
看一个Socket简单的通信图解
1.服务端welcoming socket 开始监听端口(负责监听客户端连接信息)
2.客户端client socket连接服务端指定端口(负责接收和发送服务端消息)
3.服务端welcoming socket 监听到客户端连接,创建connection socket。(负责和客户端通信)
服务器端的Socket(至少需要两个)
一个负责接收客户端连接请求(但不负责与客户端通信)
每成功接收到一个客户端的连接便在服务端产生一个对应的负责通信的Socket 在接收到客户端连接时创建. 为每个连接成功的客户端请求在服务端都创建一个对应的Socket(负责和客户端通信).
客户端的Socket
客户端Socket 必须指定要连接的服务端地址和端口。 通过创建一个Socket对象来初始化一个到服务器端的TCP连接。
Socket的通讯过程
服务器端:
申请一个socket 绑定到一个IP地址和一个端口上 开启侦听,等待接授连接
客户端: 申请一个socket 连接服务器(指明IP地址和端口号)
服务器端接到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通讯,原监听socket继续监听。
socket是一个很抽象的概念。来看看socket的位置
好吧。我承认看一系列的概念是非常痛苦的,现在开始编码咯
看来编码前还需要看下sokcet常用的方法
Socket方法: 1)IPAddress类:包含了一个IP地址 例:IPAddress ip = IPAddress.Parse(txtServer.Text);//将IP地址字符串转换后赋给ip 2) IPEndPoint类:包含了一对IP地址和端口号 例:IPEndPoint point = new IPEndPoint(ip, int.Parse(txtPort.Text));//将指定的IP地址和端口初始化后赋给point 3)Socket (): 创建一个Socket 例:Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建监听用的socket 4) Bind(): 绑定一个本地的IP和端口号(IPEndPoint) 例:socket.Bind(point);//绑定ip和端口 5) Listen(): 让Socket侦听传入的连接尝试,并指定侦听队列容量 例: socket.Listen(10); 6) Connect(): 初始化与另一个Socket的连接 7) Accept(): 接收连接并返回一个新的socket 例:Socket connSocket =socket .Accept (); 8 )Send(): 输出数据到Socket 9) Receive(): 从Socket中读取数据 10) Close(): 关闭Socket (销毁连接)
首先创建服务端,服务端是用来监听客户端请求的。
创建服务器步骤: 第一步:创建一个Socket,负责监听客户端的请求,此时会监听一个端口 第二步:客户端创建一个Socket去连接服务器的ip地址和端口号 第三步:当连接成功后。会创建一个新的socket。来负责和客户端通信

- 1 public static void startServer()
- 2 {
- 3
- 4 //第一步:创建监听用的socket
- 5 Socket socket = new Socket
- 6 (
- 7 AddressFamily.InterNetwork, //使用ip4
- 8 SocketType.Stream,//流式Socket,基于TCP
- 9 ProtocolType.Tcp //tcp协议
- 10 );
- 11
- 12 //第二步:监听的ip地址和端口号
- 13 //ip地址
- 14 IPAddress ip = IPAddress.Parse(_ip);
- 15 //ip地址和端口号
- 16 IPEndPoint point = new IPEndPoint(ip, _point);
- 17
- 18 //绑定ip和端口
- 19 //端口号不能占用:否则:以一种访问权限不允许的方式做了一个访问套接字的尝试
- 20 //通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
- 21 try
- 22 {
- 23 socket.Bind(point);
- 24 }
- 25 catch (Exception)
- 26 {
- 27
- 28 if (new IOException().InnerException is SocketException)
- 29 Console.WriteLine("端口被占用");
- 30 }
- 31 //socket.Bind(point);
- 32
- 33 //第三步:开始监听端口
- 34
- 35 //监听队列的长度
- 36 /*比如:同时有3个人来连接该服务器,因为socket同一个时间点。只能处理一个连接
- 37 * 所以其他的就要等待。当处理第一个。然后在处理第二个。以此类推
- 38 *
- 39 * 这里的10就是同一个时间点等待的队列长度为10,即。只能有10个人等待,当第11个的时候。是连接不上的
- 40 */
- 41 socket.Listen(10);
- 42
- 43 string msg = string.Format("服务器已经启动........\n监听ip为:{0}\n监听端口号为:{1}\n", _ip, _point);
- 44 showMsg(msg);
- 45
- 46 Thread listen = new Thread(Listen);
- 47 listen.IsBackground = true;
- 48 listen.Start(socket);
- 49
- 50 }

观察上面的代码。开启了一个多线程。去执行Listen方法,Listen是什么?为什么要开启一个多线程去执行?
回到上面的 "Socket的通讯过程"中提到的那个图片,因为有两个地方需要循环执行
第一个:需要循环监听来自客户端的请求
第二个:需要循环获取来自客服端的通信(这里假设是客户端跟服务器聊天)
额。这跟使用多线程有啥关系?当然有。因为Accept方法。会阻塞线程。所以用多线程,避免窗体假死。你说呢?
看看Listen方法

- 1 /// <summary>
- 2 /// 多线程执行
- 3 /// Accept方法。会阻塞线程。所以用多线程
- 4 /// </summary>
- 5 /// <param name="o"></param>
- 6 static void Listen(object o)
- 7 {
- 8 Socket socket = o as Socket;
- 9
- 10 //不停的接收来自客服端的连接
- 11 while (true)
- 12 {
- 13 //如果有客服端连接,则创建通信用是socket
- 14 //Accept方法。会阻塞线程。所以用多线程
- 15 //Accept方法会一直等待。直到有连接过来
- 16 Socket connSocket = socket.Accept();
- 17
- 18 //获取连接成功的客服端的ip地址和端口号
- 19 string msg = connSocket.RemoteEndPoint.ToString();
- 20 showMsg(msg + "连接");
- 21
- 22 //获取本机的ip地址和端口号
- 23 //connSocket.LocalEndPoint.ToString();
- 24
- 25 /*
- 26 如果不用多线程。则会一直执行ReceiveMsg
- 27 * 就不会接收客服端连接了
- 28 */
- 29 Thread th = new Thread(ReceiveMsg);
- 30 th.IsBackground = true;
- 31 th.Start(connSocket);
- 32
- 33 }
- 34 }

细心的你在Listen方法底部又看到了一个多线程。执行ReceiveMsg,对,没错。这就是上面说的。循环获取消息
ReceiveMsg方法定义:

- 1 /// <summary>
- 2 /// 接收数据
- 3 /// </summary>
- 4 /// <param name="o"></param>
- 5 static void ReceiveMsg(object o)
- 6 {
- 7 Socket connSocket = o as Socket;
- 8 while (true)
- 9 {
- 10
- 11 //接收数据
- 12 byte[] buffer = new byte[1024 * 1024];//1M
- 13 int num = 0;
- 14 try
- 15 {
- 16 //接收数据保存发送到buffer中
- 17 //num则为实际接收到的字节个数
- 18
- 19 //这里会遇到这个错误:远程主机强迫关闭了一个现有的连接。所以try一下
- 20 num = connSocket.Receive(buffer);
- 21 //当num=0.说明客服端已经断开
- 22 if (num == 0)
- 23 {
- 24 connSocket.Shutdown(SocketShutdown.Receive);
- 25 connSocket.Close();
- 26 break;
- 27 }
- 28 }
- 29 catch (Exception ex)
- 30 {
- 31 if (new IOException().InnerException is SocketException)
- 32 Console.WriteLine("网络中断");
- 33 else
- 34 Console.WriteLine(ex.Message);
- 35 break;
- 36 }
- 37
- 38 //把实际有效的字节转化成字符串
- 39 string str = Encoding.UTF8.GetString(buffer, 0, num);
- 40 showMsg(connSocket.RemoteEndPoint + "说:\n" + str);
- 41
- 42
- 43
- 44 }
- 45 }

提供服务器的完整代码如下:

- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.Linq;
- 4 using System.Text;
- 5 using System.Net.Sockets;
- 6 using System.Net;
- 7 using System.Threading;
- 8 using System.IO;
- 9 namespace CAServer
- 10 {
- 11 class Program
- 12 {
- 13
- 14 //当前主机ip
- 15 static string _ip = "192.168.1.2";
- 16 //端口号
- 17 static int _point = 8000;
- 18
- 19 static void Main(string[] args)
- 20 {
- 21 //Thread thread = new Thread(startServer);
- 22 //thread.Start();
- 23
- 24 startServer();
- 25
- 26 Console.ReadLine();
- 27
- 28 }
- 29
- 30 public static void startServer()
- 31 {
- 32
- 33 //第一步:创建监听用的socket
- 34 Socket socket = new Socket
- 35 (
- 36 AddressFamily.InterNetwork, //使用ip4
- 37 SocketType.Stream,//流式Socket,基于TCP
- 38 ProtocolType.Tcp //tcp协议
- 39 );
- 40
- 41 //第二步:监听的ip地址和端口号
- 42 //ip地址
- 43 IPAddress ip = IPAddress.Parse(_ip);
- 44 //ip地址和端口号
- 45 IPEndPoint point = new IPEndPoint(ip, _point);
- 46
- 47 //绑定ip和端口
- 48 //端口号不能占用:否则:以一种访问权限不允许的方式做了一个访问套接字的尝试
- 49 //通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
- 50 try
- 51 {
- 52 socket.Bind(point);
- 53 }
- 54 catch (Exception)
- 55 {
- 56
- 57 if (new IOException().InnerException is SocketException)
- 58 Console.WriteLine("端口被占用");
- 59 }
- 60 //socket.Bind(point);
- 61
- 62 //第三步:开始监听端口
- 63
- 64 //监听队列的长度
- 65 /*比如:同时有3个人来连接该服务器,因为socket同一个时间点。只能处理一个连接
- 66 * 所以其他的就要等待。当处理第一个。然后在处理第二个。以此类推
- 67 *
- 68 * 这里的10就是同一个时间点等待的队列长度为10,即。只能有10个人等待,当第11个的时候。是连接不上的
- 69 */
- 70 socket.Listen(10);
- 71
- 72 string msg = string.Format("服务器已经启动........\n监听ip为:{0}\n监听端口号为:{1}\n", _ip, _point);
- 73 showMsg(msg);
- 74
- 75 Thread listen = new Thread(Listen);
- 76 listen.IsBackground = true;
- 77 listen.Start(socket);
- 78
- 79 }
- 80 /// <summary>
- 81 /// 多线程执行
- 82 /// Accept方法。会阻塞线程。所以用多线程
- 83 /// </summary>
- 84 /// <param name="o"></param>
- 85 static void Listen(object o)
- 86 {
- 87 Socket socket = o as Socket;
- 88
- 89 //不停的接收来自客服端的连接
- 90 while (true)
- 91 {
- 92 //如果有客服端连接,则创建通信用是socket
- 93 //Accept方法。会阻塞线程。所以用多线程
- 94 //Accept方法会一直等待。直到有连接过来
- 95 Socket connSocket = socket.Accept();
- 96
- 97 //获取连接成功的客服端的ip地址和端口号
- 98 string msg = connSocket.RemoteEndPoint.ToString();
- 99 showMsg(msg + "连接");
- 100
- 101 //获取本机的ip地址和端口号
- 102 //connSocket.LocalEndPoint.ToString();
- 103
- 104 /*
- 105 如果不用多线程。则会一直执行ReceiveMsg
- 106 * 就不会接收客服端连接了
- 107 */
- 108 Thread th = new Thread(ReceiveMsg);
- 109 th.IsBackground = true;
- 110 th.Start(connSocket);
- 111
- 112 }
- 113 }
- 114 /// <summary>
- 115 /// 接收数据
- 116 /// </summary>
- 117 /// <param name="o"></param>
- 118 static void ReceiveMsg(object o)
- 119 {
- 120 Socket connSocket = o as Socket;
- 121 while (true)
- 122 {
- 123
- 124 //接收数据
- 125 byte[] buffer = new byte[1024 * 1024];//1M
- 126 int num = 0;
- 127 try
- 128 {
- 129 //接收数据保存发送到buffer中
- 130 //num则为实际接收到的字节个数
- 131
- 132 //这里会遇到这个错误:远程主机强迫关闭了一个现有的连接。所以try一下
- 133 num = connSocket.Receive(buffer);
- 134 //当num=0.说明客服端已经断开
- 135 if (num == 0)
- 136 {
- 137 connSocket.Shutdown(SocketShutdown.Receive);
- 138 connSocket.Close();
- 139 break;
- 140 }
- 141 }
- 142 catch (Exception ex)
- 143 {
- 144 if (new IOException().InnerException is SocketException)
- 145 Console.WriteLine("网络中断");
- 146 else
- 147 Console.WriteLine(ex.Message);
- 148 break;
- 149 }
- 150
- 151 //把实际有效的字节转化成字符串
- 152 string str = Encoding.UTF8.GetString(buffer, 0, num);
- 153 showMsg(connSocket.RemoteEndPoint + "说:\n" + str);
- 154
- 155
- 156
- 157 }
- 158 }
- 159 /// <summary>
- 160 /// 显示消息
- 161 /// </summary>
- 162 static void showMsg(string msg)
- 163 {
- 164 Console.WriteLine(msg);
- 165 //Console.ReadKey();
- 166 }
- 167 }
- 168 }

运行代码。显示如下
是不是迫不及待的想试试看效果。好吧其实我也跟你一样,cmd打开dos命令提示符,输入
telnet 192.168.1.2 8000
回车,会看到窗体名称变了
然后看到服务器窗口
然后在客户端输入数字试试
我输入了1 2 3 。当然,在cmd窗口是不显示的。这不影响测试。
小技巧:为了便于测试,可以创建一个xx.bat文件。里面写命令
telnet 192.168.1.2 8000
这样只有每次打开就会自动连接了。
当然。这仅仅是测试。现在写一个客户端,
创建一个winfrom程序,布局如下显示
请求服务器代码就很容易了。直接附上代码

- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.ComponentModel;
- 4 using System.Data;
- 5 using System.Drawing;
- 6 using System.Linq;
- 7 using System.Text;
- 8 using System.Windows.Forms;
- 9 using System.Net;
- 10 using System.Net.Sockets;
- 11
- 12 namespace WFAClient
- 13 {
- 14 public partial class Form1 : Form
- 15 {
- 16 public Form1()
- 17 {
- 18 InitializeComponent();
- 19 }
- 20 Socket socket;
- 21 private void btnOk_Click(object sender, EventArgs e)
- 22 {
- 23 //客户端连接IP
- 24 IPAddress ip = IPAddress.Parse(tbIp.Text);
- 25
- 26 //端口号
- 27 IPEndPoint point = new IPEndPoint(ip, int.Parse(tbPoint.Text));
- 28
- 29 socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- 30
- 31 try
- 32 {
- 33 socket.Connect(point);
- 34 msg("连接成功");
- 35 btnOk.Enabled = false;
- 36 }
- 37 catch (Exception ex)
- 38 {
- 39 msg(ex.Message);
- 40 }
- 41 }
- 42 private void msg(string msg)
- 43 {
- 44 tbMsg.AppendText(msg);
- 45
- 46 }
- 47
- 48 private void btnSender_Click(object sender, EventArgs e)
- 49 {
- 50 //发送信息
- 51 if (socket != null)
- 52 {
- 53 byte[] buffer = Encoding.UTF8.GetBytes(tbContent.Text);
- 54 socket.Send(buffer);
- 55 /*
- 56 * 如果不释放资源。当关闭连接的时候
- 57 * 服务端接收消息会报如下异常:
- 58 * 远程主机强迫关闭了一个现有的连接。
- 59 */
- 60 //socket.Close();
- 61 //socket.Disconnect(true);
- 62 }
- 63 }
- 64 }
- 65 }

运行测试,这里需要同时运行客户端和服务器,
首先运行服务器,那怎么运行客户端呢。
右键客户端项目。调试--》启用新实例
好了。一个入门的过程就这样悄悄的完成了。
以上内容来自:http://www.cnblogs.com/nsky/p/4501782.html
根据上面的内容,已经可以开发出一个可以正常通信的Socket示例了,
接下来首先要考虑的就是服务器性能问题
1)在服务器接收数据的时候,定义了一个1M的Byte Buffer,有些设计的更大。更大Buffer可以保证客户端发送数据量很大的情况全部能接受完全。但是作为一个服务器每收到一条客户端请求,都要申请一个1M的Buffer去装客户端发送的数据。如果客户端的并发量很大的情况,还没等到网络的瓶颈,服务器内存开销已经吃不消了。
对于这个问题的解决思路是:
定义一个小Buffer,每次接受客户端请求用:
byte[] bufferTemp = new byte[1024];
和一个大Buffer,装客户端的所有数据,其中用到了strReceiveLength,是客户端发送的总长度,稍后再解释:
byte[] buffer = new byte[Convert.ToInt32(strReceiveLength)];
改写while (true)循环,每次接受1K的数据,然后用Array.Copy方法,把bufferTemp中的数据复制给buffer:
num = connSocket.Receive(bufferTemp, SocketFlags.None);
ArrayUtil.ArrayCopy(bufferTemp, buffer, check, num);
check += num;
这个Array.Copy是重点,因为TCP数据流在传输过程中也是一个包一个包的传送,最大不超过8K。所以每次接受到的数据,也就是bufferTemp这个变量有可能装满,也有可能装不满。所以在拷贝的时候一定按照这次接受的长度顺序的放入buffer中。等到客户端全部数据发送完成后,再把buffer转换:
strReceive = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
而不能够每次都转换,再strReceive += 一个Byte数组。这样做的后果就是中文会被截断,因为中文在UTF-8编码下占3-4个字节,很容易出现乱码。
2)数据长度校验
TCP在传输过程中难免会有数据发送不全或者丢失的情况。所以在客户端发送数据的时候一定带上校验长度:
byte[] btyLength = Encoding.UTF8.GetBytes(strContent);
string strLength = btyLength.Length.ToString().PadLeft(8, '0');
string sendData = strLength + strContent;
byte[] buffer = Encoding.UTF8.GetBytes(sendData);
socketClient.Send(buffer);
这样在服务器端,先把要接受的长度收到:
byte[] bufferLength = new byte[8];
num = connSocket.Receive(bufferLength);
strReceiveLength = Encoding.UTF8.GetString(bufferLength, 0, bufferLength.Length);
在循环里用下面的判断,来校验和判断是否已经接受完毕:
if (check == Convert.ToInt32(strReceiveLength))
3)设计上一些方式
很多局域网的部署是分层的,也就是分内网和外网。服务器部署一定要在外网上部署,这里的外网指的是在客户端之上的网段上。
比如192.168.1.22下有个无线路由,无线连接的IP段为192.168.2.1~254
服务器搭建在192.168.1网段下,192.168.2的客户端是可以访问的。但是相反则不行,192.168.1网段下的设备无法主动找到192.168.2的服务器。
Socket 由浅入深,开发一个真正的通信应用的更多相关文章
- 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室
原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室
原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- 使用React、Node.js、MongoDB、Socket.IO开发一个角色投票应用的学习过程(三)
这几篇都是我原来首发在 segmentfault 上的地址:https://segmentfault.com/a/1190000005040834 突然想起来我这个博客冷落了好多年了,也该更新一下,呵 ...
- python socket编程---从使用Python开发一个Socket示例说到开发者的思维和习惯问题
今天主要说的是一个开发者的思维和习惯问题. 思维包括编程的思维和解决一个具体问题的分析思维,分析思路,分析方法,甚至是分析工具. 无论是好习惯还是不好的习惯,都是在者一天一天的思维中形成的.那些不好的 ...
- 如何在嵌入式Linux上开发一个语音通信解决方案
开发一个语音通信解决方案是一个软件项目.既然是软件项目,就要有相应的计划:有多少功能,安排多少软件工程师去做,这些工程师在这一领域的经验如何,是否需要培训,要多长时间做完,中间有几个主要的milest ...
- Python之路,Day18 - 开发一个WEB聊天来撩妹吧
Python之路,Day18 - 开发一个WEB聊天来撩妹吧 本节内容: 项目实战:开发一个WEB聊天室 功能需求: 用户可以与好友一对一聊天 可以搜索.添加某人为好友 用户可以搜索和添加群 每个 ...
- python 开发一个支持多用户在线的FTP
### 作者介绍:* author:lzl### 博客地址:* http://www.cnblogs.com/lianzhilei/p/5813986.html### 功能实现 作业:开发一个支持多用 ...
- Socket 由浅入深系列--------- 简单实现编程(三)
socket 由浅入深 原理(一)介绍了一些,以下也就是简单实现,并未考虑其它性能化! 使用TCP的server客户机举例 server 设置一个简单的TCPserver涉及下列步骤: 调用 sock ...
- 基于线程开发一个FTP服务器
一,项目题目:基于线程开发一个FTP服务器 二,项目要求: 基本要求: 1.用户加密认证 2.允许同时多用户登录 3.每个用户有自己的家目录 ,且只能访问自己的家目录 4.对用户进行磁盘配 ...
随机推荐
- Go的100天之旅-03变量
变量 变量介绍 变量这个词来源于数学,类似方程中的x.y,代表的是存储在计算机中的值.这里主要介绍Go和其它编程语言不一样的地方,在前面我们提到过,Go是一门静态语言.静态语言区别动态语言一个重要的特 ...
- C++ 线性筛素数
今天要写一篇亲民的博客了,尽力帮助一下那些不会线性筛素数或者突然忘记线性筛素数的大佬. 众所周知,一个素数的倍数肯定不是素数(废话).所以我们可以找到一个方法,普通的筛法(其实不算筛,普通的是判断一个 ...
- vue : 项目起手式 - router组件通用模板
每次新建文件都要找来找去,麻烦,干脆贴到这里好了. <template> <div id="page"> </div> </templat ...
- coding如何绑定二次验证码_虚拟MFA_两步验证_身份验证?
Coding.net 是一个面向开发者的云端开发平台,提供 Git/SVN 代码托管.任务管理.在线 WebIDE.Cloud Studio.开发协作.文件管理.Wiki 管理.提供个人服务及企业管理 ...
- JavaSE基础知识之修饰符和使用场景,你真的了解嘛
修饰符的作用是啥? 用来定义类.方法或者变量的访问权限 两大类 访问修饰符 限定类.属性或方法是否可以被程序里的其他部分访问和调用的修饰符 private<default<protecte ...
- .net core 拦截socket
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net ...
- vue学习(九) 使用内联样式设置style样式
/html <div id="app"> //对象就是无序键值对的集合 <h1 :style="{ color:red, 'font-weight':2 ...
- Bug--时区问题导致IDEA连接数据库失败
打开cmd进入mysql,设置 set global time_zone='+8:00';
- C#中Session的用法详细介绍
Session模型简介 在学习之前我们会疑惑,Session是什么呢?简单来说就是服务器给客户端的一个编号.当一台WWW服务器运行时,可能有若干个用户浏览正在运正在这台服务器上的网站.当每 个用户首次 ...
- 页面上怎么使用svg
svg标签直接在页面使用 不多说. 其他标签使用svg 除了直接使用svg标签,还有如下方法: <object data="your.svg" type="imag ...