到昨天为止Lis的编写就告一个段落了。回顾这一个月,虽然有所事事,但具体干了什么,学到了什么,直接说出来,还是不容易的。
最可以独立出来的一个知识点就是socket通信了。
Socket通信是客户端与服务器之间的通信,客户端在服务器的某个端口找某种服务,如图,用一个不恰当的比喻,就像某个人在琅琊阁的某个书架的锦盒中寻找某种指示。
image.png
image.png
socket可以用于本机内部通信,也可以用于网络。具体的协议我也不清楚,也没有深究。
编写socket客户端分下列几步。我用的语言是C#,想来所有的语言都差不多是这样的。
步骤一、openConnestion
我觉得在这个步骤中比较关键的有。
绑定服务器IP地址和端口号。(C#:serverSocket.Bind(IPAdress:Port))。
启动监听。(C#:serverSocket.Listen(n))
n是设定排队连接请求最多可以有n个,指没连上但等待连接的最多有n个,不是指这个端口能够容纳的连接数只有n个。至于服务器端口最多容纳多少个连接,据说是65535个。
步骤二、acceptClientSocket
新建一个线程,非常关键,因为我们循环接收来自端口的客户端连接请求,不新建线程服务器软件就无法进行与socket无关的动作,比如GUI操作。
不断接收客户端的socket。
C#:
While(true)
{
……
Socket clientSocket = serverSocket.Accept();
……
}
3.创建接收线程,接收数据。之所以要创建新的接收线程,是因为接收的关键语句receive是阻塞的(至少C#是这样,想来其他的语言都差不多)。
步骤三、Receive对接收线程的处理
对接收线程的处理有好几种思路,我使用过两种:A. 每一个客户端就新建一条接收线程;B. 通过IO复用(比如select方法)所有客户端都采用同一条线程监听。
方法A,关键语句C#:int receiveNumber =myClientSocket.Receive(接收内存缓冲区)。
这个方法,myClientSocket端口无数据时,则阻塞,有数据则返回数据个数,理论上断开则返回-1,但不知道为啥从来没有真正返回过,每次断开都报异常。
方法B,关键语句C#:Socket.Select(socket客户端的接收链表, socket客户端的发送链表,socket客户端的异常链表, 允许的阻塞时间),前三个链表可以有两个为null。
当接收链表中任何一个socket都没有收到数据时,阻塞,收到数据之后即返回,并且参数“socket客户端的接收链表”会改为“接收到数据的socket客户端链表”。因此,再写一个循环语句,循环读取接收到的数据:
for(int i = 0; i <readList.Count; i++)
{
myClientSocket = (Socket)readList[i];
int receiveNumber =myClientSocket.Receive(接收内存缓冲区);
……
}
Select语句不是阻塞的,没一个客户端接收区有数据的话会返回socket客户端的接收链表readList.Count=0。但重点是,用了select语句就能节约很多个接收线程,避免时间片轮转到阻塞的Receive语句上,从而使得接收到的数据能更快得到处理。
还有第三种方法:IOCP(windows)、epoll(linux),略有耳闻,没有用过。
步骤三、处理接收到的信息。
视情况而定,没啥好说的。
步骤四、send发送消息
image.png
我使用的是一个客户端对于一个发送线程,平时休眠,发送队列有消息的时候就醒过来发送消息,发完再休眠。
关键语句C#:myClientSocket.Send(Encoding.ASCII.GetBytes(sendMessage字符串))。
就这样吧。2017年8月24日。
网友评论