程序上对于网络编程是怎么封装的?
一般的网络编程都叫socket编程。这就有了一个新的概念叫做socket。这一个新概念应用非常广泛。unix上linux上网络编程叫socket编程。windows上网络编程也叫socket编程。JAVA上的网络编程也叫socket编程。所以socket已经接受到了广泛的认可,一般的网络编程我们都叫socket编程。
socket什么意思?英文什么意思 ?插座,插座的意思,不信你可以查一下。
那这就可以想象了 socket到底是什么意思呢?
两个JAVA应用程序或两个应用程序或者说任意应用程序,通过一个双向的网络通信实现数据交换,双向链路的一端称为一个socket。
现在咱们两台机器,互相之间可以通讯,怎么样通讯呢?
链路的一端称做一个socket,socket就是插座的意思,这就好比上说在我的上面有一个插座,在你的上面有一个插座。咱们之间互相之间怎么连起来呢?这样来连,有一条线一段插在你的插座上,这条线的另一端插到我的插座上,咱们之间因这条线连了起来,所以这个叫做socket编程。
socket编程的概念知道谁先提出来吗?
现在大多数是c语言的开发包,但是window上,VC上也都支持这个开发包,unix上也是这个开发包,伯克利大学的socket开发包应用得十分十分广泛。unix上linux上都对这个开发包予以支持,你都可以采用它的API,C语言的API来直接应用它,它的应用十分广泛,原来C语言程序一直用的就是它,linux上unix上windows上也可以用,非常好用的一套东西。
当然伯克利大学对计算机界的贡献是十分大的,除了非常著名的socket包以外,还有其他的听过Berkeley DB吗?Database、Berkeley DB很多现在的数据库都是起源于Berkeley DB。听过freebsd吗?是unix开源的的一个分支,unix分支现在有上百种,freebsd是其中一种,开源的。这都是伯克利大学所做的贡献。
这个链路中的一端好比一个插座一样,拿跟线两端一插,ok咱们连一起了。所以这个叫socket编程。socket通常用来实现client-server连接,一个是server一个是client,我连接到你上面,那大家互相之间的链路就已经通了。
在JAVA里面多有跟网络编程有关的类,全部都在这个java.net里面,打开java.net这个包,跟网络相关的类都位于这里面。
https://nowjava.com/docs/java-api-11/java.base/java/net/package-summary.html
java.net里面定义了两个类,一个socket一个是serversocket。
socket可以用在client端,client这一端的插座
serversocket是TCP服务器端的插座,所以serversocket是用来实现tcp连接的,对于UDP来说 严格意义上没有所谓的客户端client和服务端server,互相之间发信息,我发给你了 就完了。
我说你是我的server只是逻辑上来讲,我把东西发到你那去,由你来转发或由你来处理所以你叫server,这是逻辑意义上的。但从技术上讲只有TCP才分client和server。server在TCP上它这的插座叫serversocket,client端这个插座它就叫socket。TCP client端的插座就叫socket。
建立连接时所需的寻址地址为远程计算机的IP地址和端口号(Port Number)
端口号又是干嘛使的?
这个端口号比较重要,比方说我问你这么个小小的问题,我机有QQ和MSN你的机上有qq和MSN,我QQ发数据给你为什么你的MSN没收到,QQ收到了,如果只用IP来区分咱们两台机器的话,那我说句话你那边任何一个程序都可以收到对不对,我QQ说的话为什么没跑到你的MSN上?这是为什么呢?这就说明在这个机器上还有一个东西在区分不同的应用程序。
那谁来做区分?
端口号来做区分。端口号在计算机内部两个字节,所以两个字节最多有多少个端口号呢?65536个,一台机器上最多有65536个端口号,一个应用程序可以占用多个端口号。假设一个应用程序就占一个端口号,最多你的机上能装多少个网络程序啊,能运行多少个?65536个。足够了你见过水的手机上跑了65536个网络应用程序的吗?六万多个,那这个机器不用动了。
端口号是来区分同一台机器上不同的应用程序。端口号资源有一台已经占了其它程序就占不了了。
咱们自己编写程序的时候,你要占端口号1024以上的,1024以下的不要占。为什么?因为1024一下的系统会随时征用,有一些其他应用已经占领这个端口号了系统要用,你要用就用1024以上的。
有些应用非常的有名,这些端口号基本上给他们用了,比方说80端口,干嘛的?就是网络上http网页,你如果想访问百度的端口号是这么来访问http://www.baidu.com:80
实际上你敲不敲80是一样的,它默认http端口为80端口,比方说还有其他协议的端口,21是哪个协议的端口啊?FTP。SMTP知道是什么意思吗?SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,那这个协议是什么端口?25。POP3协议呢?110。这些都是非常著名的端口。
所以咱么自己要用端口号怎么用呢?用1024以后的,你不要用1024以前的。
端口号本身分两种,一种是TCP端口一种是UDP端口,所以TCP端口有六万多个,UDP端口也有六万多个 。TCP的某一个端口8888,UDP也有一个端口8888他们两个端口不是一回事,所以TCP端口和UDP端口是分开的每一个是65536个,所以严格意义上你的机器上可以跑十三多万个网络应用程序,如果你的机器撑得住的话。
我们看java怎么封装这些网络编程的。
首先先启动server再启动client。
server启动在那里就不动了,它就等待客户端的连接。serversocket是阻塞式的,没有客户端连上它就在那里傻等,这叫serversocket。新建一个serversocket往往我们会给一个端口号,指定一个端口号的意思是什么呢?你一个serversocket不能说占用了所有的端口,你占那个端口,你通过那个端口来监听客户端的连接,你都得告诉一声,不可能所有的server端口都给你占了,所以这个serversocket在哪个端口上来监听客户端的连接得指定好。给它一个比较吉利的端口8888
public class TCPServer {
public static void main(String[] args) throws IOException {
//1.创建服务器ServerSocket对象和系统要指定的端口号
ServerSocket server = new ServerSocket(8888)
}
}
这一段代码写完 服务器已经开始监听了
客户端程序的插座叫做socket,新建一个socket对象并制定要连接的服务器的IP和端口号。IP若用127.0.0.1这个叫本地ip连上自己的机器,然后后面指定一个端口,指定你要连接到那个端口上
public class TCPClient {
public static void main(String[] args) throws IOException {
//1.创建一个客户端对象Socket,构造方法需要绑定服务器的IP地址和端口号
Socket socket = new Socket("127.0.0.1",8888);
}
}
这一段代码写完 就是客户端申请一个连接,连接到127.0.0.1:8888这台服务器上,通过自身的端口连接到对方的端口上,两端这个连接就已经建立了。client这个端口是哪个端口呢?客户端这个端口系统随机选择,没有必要把客户端绑在哪个端口上才能跟服务器连接,随便找个端口跟服务器连一下就可以了,因为一旦占用了某个端口,那这个端口就为我所用了,服务器发任何东西过来也可以发到client端的端口上不会发到别的地儿去。
现在client端已经申请和服务端连接了,可是服务器接受或不接受它这也难说。
server端:client端已经申请连接我了,那我应该接受client端的连接请求,利用serversocket里面的accept方法,它的返回值是一个socket类型。
这个accept方法是干什么使的?
作为一个服务器端来说,它可以接受很多很多客户端的连接。多个客户端可以连接同一个服务器端。
客户端请求申请连接的时候,服务器端接受不接受,由server端说了算,怎么样接受?
进来用accept这个方法。你申请连接我的时候,我如果不accept你,对不起咱们具体的连接建立不起来。我如果accept了,比如说一个客户端连接我,我服务器端accept了,那服务器这一端建立了一个插座,这个插座专门跟这个客户端做连接,那服务器端就可以跟和客户端来回的通话了,如果有另外一个客户端连接进来,那服务器端就再accept一下,那到底要accept多少下才能把客户端都接进来呢,所以服务器的程序往往是死循环不断在那里accept,有客户端来连接就accept,所以这就是为什么server那一边是365天24小时不间断,只有死循环才能不间断。
服务器端克客户端已经建立起连接了,那这两者如何进行对话呢?
通过管道通过流来说话。当一个客户端连接,连接到服务器端以后,在这个连接的管道上面有两根管道,一根输出管道一根输入管道。
下方代码实现基于cocket的TCP通信
//2.使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
//用来发送数据给服务器
OutputStream os = socket.getOutputStream();
我们getOutputStream拿到管道里的OutputStream()里面的输出流。拿getInputStream()拿到管道里的输入流,双方通过输入输出流进行交互,通信完了记得关掉输入输出流和socket。
package TCP;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author yxx
* @date 2020/6/26-3:39
*/
/*
TCP通信的服务器端:接收客户端的请求,读取客户端发送的数据,给客户端回写数据
表示服务器的类:
java.net.ServerSocket:此类实现服务器套接字。
构造方法:
ServerSocket(int port) 创建绑定到特定端口的服务器套接字。
服务器端必须明确一件事情,必须的知道是哪个客户端请求的服务器
所以可以使用accept方法获取到请求的客户端对象Socket
成员方法:
Socket accept() 侦听并接受到此套接字的连接。
服务器的实现步骤:
1.创建服务器ServerSocket对象和系统要指定的端口号
2.使用ServerSocket对象中的方法accept,获取到请求的客户端对象Socket
3.使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
4.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据
5.使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
6.使用网络字节输出流OutputStream对象中的方法write,给客户端回写数据
7.释放资源(Socket,ServerSocket)
*/
public class TCPServer {
public static void main(String[] args) throws IOException {
//1.创建服务器ServerSocket对象和系统要指定的端口号
ServerSocket server = new ServerSocket(8888);
//2.使用ServerSocket对象中的方法accept,监听客户端连接,获取到请求的客户端对象Socket
Socket socket = server.accept();//该方法是一个阻塞的方法,如果没有客户端连接,将一直等待
System.out.println("客户端连接成功!!");
//3.使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象,
// 用来接受该客户端发送给服务器的数据
InputStream is = socket.getInputStream();
//通信:接收数据
//4.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes,0,len));
//5.使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象,
// 用来发送给数据给客户端
OutputStream os = socket.getOutputStream();
//通信:发送数据
//6.使用网络字节输出流OutputStream对象中的方法write,给客户端回写数据
os.write("收到谢谢".getBytes());
//7.释放资源(Socket,ServerSocket)
//关闭socket,不再与客户端通信,socket关闭,意味着InputStream和OutputStream也关闭了
socket.close();
//如果不再接受任何客户端通信,可以关闭ServerSocket
server.close();
}
}
package TCP;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* @author yxx
* @date 2020/6/26-3:38
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/*
TCP通信的客户端:向服务器发送连接请求,给服务器发送数据,读取服务器回写的数据
表示客户端的类:
java.net.Socket:此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
套接字:包含了IP地址和端口号的网络单位
构造方法:
Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。
参数:
String host:服务器主机的名称/服务器的IP地址
int port:服务器的端口号
成员方法:
OutputStream getOutputStream() 返回此套接字的输出流。
InputStream getInputStream() 返回此套接字的输入流。
void close() 关闭此套接字。
实现步骤:
1.创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口号
2.使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
3.使用网络字节输出流OutputStream对象中的方法write,给服务器发送数据
4.使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
5.使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据
6.释放资源(Socket)
注意:
1.客户端和服务器端进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象
2.当我们创建客户端对象Socket的时候,就会去请求服务器和服务器经过3次握手建立连接通路
这时如果服务器没有启动,那么就会抛出异常ConnectException: Connection refused: connect
如果服务器已经启动,那么就可以进行交互了
*/
public class TCPClient {
public static void main(String[] args) throws IOException {
//1.创建一个客户端对象Socket,构造方法需要绑定服务器的IP地址和端口号
Socket socket = new Socket("127.0.0.1",8888);
//2.使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
//用来发送数据给服务器
OutputStream os = socket.getOutputStream();
//3.使用网络字节输出流OutputStream对象中的方法write,给服务器发送数据
os.write("你好服务器".getBytes());
//4.使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
//用来接收服务器发送给客户端的数据
InputStream is = socket.getInputStream();
//5.使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据,接受数据
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes,0,len));
//6.释放资源(Socket)
//关闭socket,不再与服务器通信,即断开与服务器的连接
//socket 关闭,意味着InputStream和OutputStream 也关闭了
socket.close();
}
}