socket系列之socket服务端与客户端如何通信

上面已经分别介绍了ServerSocket跟Socket的工作步骤,并且从应用层往系统底层剖析其运作原理,我们清楚了他们各自的一块,现在我们将把他们结合起来,看看他们是如何通信的,并详细讨论一下他们之间相互通信的一些细节。
借助图2-3-2-4,想象一下你正在大学课室上着电脑,你跟你另外两个朋友觉得老师讲得课很菜,没必要听,于是你们仨都各自打开浏览器冲浪,刚好你们访问了同一台服务器,假如你用的是浏览器A,那么整个流程为:
① 浏览器确认目标IP跟目标端口号(http默认使用80端口),当然如果你在浏览器地址栏输入带端口的地址,那么目标端口号将是你指定的端口,另外浏览器还将组织http报文,一并将这些参数传入系统底层socket。
② 系统层socket对TCP/IP协议的操作,从前面我们已经学到,一层一层往下其实就是将报文一层一层包起来,所以这里是先用http报文组织成TCP报文,再组织成IP报文,其中socket的源端口是随机分配的(一个大于1023随机数),最后放到TCP/IP栈里,排队发送消息。
③ ServerSocket正在堵塞监听接收连接,客户端socket与之建立连接。
④ 服务器端根据客户端请求创建socket,此socket即可用于跟客户端socket进行通信。
⑤ 服务器处理相关逻辑,例如数据库操作,逻辑判断等等。
⑥ 服务器处理完,行成相应的用于客户端浏览器显示的http报文,http报文经过tcp跟ip协议包装,返回给客户端socket。
⑦ 客户端经过层层解析,把http报文传到浏览器,浏览器对http报文进行解析,最后一个漂亮整洁的网页展示在你眼前。
⑧ 释放关闭连接。
如果你们仨在同一时间访问,服务器为了能有更好地性能,为了几乎同一时间响应你们,而不是一个处理完才处理另外一个,服务器会采取多线程处理,一个线程处理一个请求。
 
图2-3-2-4 ServerSocket与Socket通信模型

上面的通信模型从较宏观的层面描述了socket之间的通信,而在通信过程中必然涉及数据报文的传输,接着将学习socket底层数据的传输模型。图2-3-2-5形象地展现了数据是怎样从应用层到系统底层,再到互联网传输的。首先先介绍两个FIFO队列:SendQ跟RecvQ。它们都处于系统底层,在传输过程中充当缓冲区的作用,SendQ是把应用层发送到系统底层的数据进行缓冲,然后排队发送到因特网的队列,而RecvQ则是把从因特网接收到的数据进行缓冲,等待应用层去读取的队列。具体步骤如下:
① 应用层的Socket或Serversocket把要发送的数据写入系统底层的SendQ队列。
② SendQ队列根据先进先出原则,把这些数据发往因特网,到达目标主机。(从传输层来看,可以认为这时的数据是TCP报文)
③ 如果有数据从因特网发送过来,首先会被接收到RecvQ队列进行缓冲。
④ 应用层的Socket或Serversocket会循环尝试读取RecvQ队列,如果有数据则读取到应用层。
从中可以总结,TCP协议其实就是负责将数据按顺序从SendQ与RecvQ之间互相转移。而且从我们应用层来看这个转移过程我们是没有办法控制或直接观察的。同时,由于TCP提供可靠的数据传输服务,所以任何写入SendQ队列的数据都必须要保留一份数据副本,直到连接的另外一端成功接收。另外,Socket通过输出流向SendQ写数据并不意味着数据已经被发送,他们仅仅只是到了缓冲区,就算Socket的输出流进行了flush()操作也不能保证数据马上被发送到信道。
 
图2-3-2-5 socket数据传输模型

那么我们能不能就认为在连接的一端写入数据,另外一端就能马上读取数据呢?接着我们将更深入探讨SendQ与RecvQ队列里面的数据是怎样传输的,这个过程应该说是以块来传输的,而这些块的大小在一定程度上独立于应用层socket读写的缓冲大小。
如图2-3-2-6,假如应用层socket调用输出流write()方法向SendQ队列写数据,三次写入的数据大小分别为1000字节、2000字节、5000字节,而假设SendQ队列的缓存块大小为3000字节,第一次1000字节加上2000字节刚好等于3000字节,那么这两次的数据作为一个块进行传输。通过因特网到达RecvQ队列,应用层socket再通过输入流的read()方法读取RecvQ里的数据,输入流缓冲区读取了RecvQ队列3000字节就返回值3000。
 
图2-3-2-6 socket底层的块传输

在现实使用中,SendQ跟RecvQ队列可能会被无限填充, 为了防止一个TCP连接将系统内存全部耗尽,必须要对SendQ跟RecvQ队列的大小进行限制。一旦RecvQ队列数达到最大值,TCP流控制就会通知SendQ先停止发送数据,等我的RecvQ中的数据被socket输入流读走了有空间了再传给我。这样就能有效地控制过量发送,有效杜绝超出系统接收处理能力的情况。对于socket输出流可以不断写入数据,直到SendQ队列被填满了,此时write()方法将会阻塞等待。

==========广告时间==========

鄙人的新书《Tomcat内核设计剖析》已经在京东预售了,有需要的朋友可以到 https://item.jd.com/12185360.html 进行预定。感谢各位朋友。

=========================

时间: 2025-01-21 05:08:28

socket系列之socket服务端与客户端如何通信的相关文章

java-使用socket通信服务端如何处理客户端请求

问题描述 使用socket通信服务端如何处理客户端请求 场景如下: 一个服务端,一个客户端通过socket连接服务端,假如客户端要请求服务端做一件事(如调用服务端A类的a方法), 因为socket传输的是字符串,所以我现在的做法是让客户端传一个标识符a到服务端,然后服务端 通过判断传过来的是a则调用A类的a方法, 如果我要执行A类的b方法,则传b过去再判断 我想问的是有没有更好的解决方案,或现成的框架可用 解决方案 如果你这样的需求,我觉得更适合HTTP.也许玩C++的更习惯于socket.之前

socket服务端向客户端发送字节数组消息时客户端无法接收问题

问题描述 socket服务端向客户端发送字节数组消息时客户端无法接收问题

视频-服务端控制客户端Socket

问题描述 服务端控制客户端Socket 服务端如何通过Socket控制客户端在某个定点时刻播放视频,如果有代码的可以分享我吗?谢谢 解决方案 本人也是最近接触Socket,懂得不多,只能给你提供一个思路. 你可以在客户端添加一个线程,使用不同于原来的的Socket Port建立一个通讯, 客户端的那个线程不断接收服务端的回传信息, 根据回传的信息在这个线程中控制你想要的进度. 解决方案二: 首先要让客户端和服务器端游一个长连接,并且要有心跳包来保证accept,之后到时间服务器端给客户端发送一个

用socket编写的客户端和服务端,客户端可以通过服务端的域名发送消息吗

问题描述 用socket编写的客户端和服务端,客户端可以通过服务端的域名发送消息吗 本来要做GPRS通信模块发送命令到服务器端,服务器端根据命令做出反应,如果命令有需要还要返回数据到Gprs模块.网上搜怎么做,都是说用sokect做,我需要的是GPRS模块通过服务器的域名发送消息到服务端. 解决方案 如果是socket的话,gethostbyname是可以将域名转换成ip地址的 解决方案二: Linux socket客户端和服务端socket通讯 客户端和服务端socket的客户端和服务端的编程

Android Socket服务端与客户端用字符串的方式互相传递图片的方法_Android

发送图片: 首先找到具体传递的图片: <span style="font-family: comic sans ms,sans-serif; font-size: 16px;">private Bitmap getimage(String srcPath) { BitmapFactory.Options newOpts = new BitmapFactory.Options(); // 开始读入图片,此时把options.inJustDecodeBounds 设回true了

java socket手机通信-关于java的问题:手机用socket连接电脑的服务端时老出现文件找不到的错误,求解决

问题描述 关于java的问题:手机用socket连接电脑的服务端时老出现文件找不到的错误,求解决 30C 解决方案 也可以私聊我.扣扣1944687725 解决方案二: 解决方案三: 你那个斜杠是不是写反了 passwdinput.dat 解决方案四: 你仔细看看出错的提示, 是读文件的时候找不到,对应的代码是在ServerThread.java的51行然后,你把路径改为绝对路径试一试,如果可以了,就是你相对路径的根目录不对.保证passwd文件夹在你的执行目录下 解决方案五: 右键 prope

bad file descriptor-使用线程的TCP回射服务端和客户端运行时错误

问题描述 使用线程的TCP回射服务端和客户端运行时错误 服务端serv.c: #include "unp.h" #include <pthread.h> void str_echo(int sockfd) { char buf[MAXLINE]; int n; while(( n = read(sockfd,buf,sizeof(buf)))>=0) { if (n ==0) { printf("client EOF,its use shutdown soc

聊天室-关于java的聊天程序,分服务端和客户端,请java大神帮我调试一下,我检查没编写错误

问题描述 关于java的聊天程序,分服务端和客户端,请java大神帮我调试一下,我检查没编写错误 //服务端 package chatApp; import java.net.*; import java.io.*; import java.util.*; public class chatserverthree implements Runnable { public static final int PORT=1234; protected ServerSocket listen; stat

tcp协议 udp协议-C#服务端请求客户端数据

问题描述 C#服务端请求客户端数据 我想在客户端安装一个服务后,能够向客户端请求数据,返回数据给服务器,这样用什么协议要好,socket行吗?服务端怎么发起这个请求,麻烦各位大神帮帮忙? 我不清楚的地方,如果用socket,保存客户端连接后,我要请求客户端数据,只能是客户端请求服务端,而我换成服务端请求客户端好像只能是客户端请求后服务端回复. 如果是UDP的话好定义请求和回复问题吗? 解决方案 ok,既然是.net,就有.net的最佳做法,wcf双工通讯或signalr.我在论坛都分享过例子.