java基础(16)- 网络编程—socket
注 : 参考自https://mp.weixin.qq.com/s/MrrN7BDcKMu8SCKs6zij_g
16.1网络相关理论基础
16.2URL类统一资源定位和Inetaddress类简介
16.3socket的通讯
16.4使用多线程监听多客户端
16.1网络相关理论基础
计算机网络就是实现了多个计算机互相连接的系统,相互连接的计算机之间彼此能够进行数据交换。把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模宏大、功能强大的网络系统,从而使众多的计算机可以方便地互相传递信息,共享硬件、软件、数据信息等资源。
没有网络的计算机世界是枯燥无聊的,正式因为有了网络才有现在这么多姿多彩的计算机世界,联网有什么作用呢,简单归纳一下:计算机的联网可以实现:1、使用远程资源;2、共享信息、程序和数据;3、分布处理。
二、网络分类
1、按照网络规模和范围可以简单划分为:
局域网(LAN,Local Area Network)
都市网(MAN,Metropolis Area Network)
广域网(WAN,Wide Area Network)
2、按照网络拓扑结构可以分为:
星型网络、总线网络、环线网络、树型网络、星型环线网络等。
3、按照传输介质划分:
双绞线、同轴电缆、光导纤维、视线介质等。
三、网络的几种工作模式
1、专用服务器结构(Server-Based)
又称为“工作站/文件服务器”结构,由若干台微机工作站与一台或多台文件服务器通过通信线路连接起来组成工作站存取服务器文件,共享存储设备。
2、客户机/服务器模式(client/server)
其中一台或几台较大的计算机集中进行共享数据库的管理和存取,称为服务器,而将其它的应用处理工作分散到网络中其它微机上去做,构成分布式的处理系统。
3、对等式网络:(Peer-to-Peer)
也称点对点服务,很多下载工具就是使用了这个技术。在对等式网络结构中,没有专用服务器 每一个工作站既可以起客户机作用也可以起服务器作用。
四、网络通信协议/接口
1、网络协议概述
世界上那么多不同型号的计算机,不同的操作系统,要实现无障碍的通讯,就必须定下一个通许的格式,这就是网络协议。网络通信协议就是计算机网络中实现通信必须有一些约定即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制标准。
就像城市里的道路有交通规则,同理,计算机网络就有计算机网络协议来规定计算机之间连接的物理、机械(网线与网卡的连接规则)等特性和计算机之间相互寻址规律、数据发生冲突的解决、数据的传送和接收等等。
网络通讯协议有很多,比较出名的是OSI参考模型规定,但是只是停留在学术研究,起到一个指导和参考的意思,由于其复杂性,并没有大范围的使用,我们在互联网中使用得最多的是TCP/IP协议。TCP/IP协议就是一个非常实用的网络协议,它是Internet所遵循的协议,是一个标准,广泛的使用在大多数的操作系统上,也用于大多数局域网。
2、TCP/IP协议简介
可以说TCP/IP协议是网络应用程序的首选协议,大多数网络程序都是以这个协议为基础的。
TCP/IP:是Internet上不同系统之间互联的一组协议。它为分散和不同类型的硬件提供了一个通用的编程接口。TCP/IP 协议使Internet尽可能成为一个分散、无序的网络。
TCP/IP通常被看成一个4层模型:应用层、传输层、网络层以及数据链路层+物理层。
TCP协议为一种可靠的端对端协议:重发一切没有收到的数据,进行数据内容准确性检查并保证分组的正确顺序。
IP协议是网络上的计算机进行连接的基础 qIP协议是不可靠的:无论传送正确与否都不进行检验、不回送确认、不保证分组的正确顺序 IP协议位于OSI参考模型的网络层
五、IP和端口
1、IP地址
要想让网络中的计算机能够相互通信,必须为每台计算机指定一个标识号,通过这个标识号来指定要接收数据的计算机和识别发送数据的计算机,在TCP/IP协议中,这个标识号就是IP地址。
为了实现Internet上不同计算机之间的通信,每台计算机都必须有一个不与其它计算机重复的地址---IP地址 qIP地址是数字型的,32位(32bit),由4个 8位的二进制数组成,每8位之间用圆点隔开。IP地址被分成了A、B、C、D、E五类,每个类别的网络标识和主机标识各有规则。
目前IP地址在计算机中用4个字节(32位的二进制数)表示,称为Ipv4.为了便于使用,我们通常取每个字节的十进制数,并且每个字节之前用圆点隔开来表示,如:192.168.1.100,202.34.34.5等。
2、端口
IP地址唯一确定了一台计算机,但是计算机上面还有很多应用程序需要网络通信的,在通信过程中,怎么现在和那个应用程序通讯呢?这就需要端口了,端口是计算机与外界交流的出入口,是一种抽象的软件结构,包括一些数据结构和I/O(基本输入/输出)缓冲区。每个应用程序只能监听一个端口,如果该端口已经让其他应用程序绑定了,那么你就不能再使用这个端口了,否则程序会报错的。
端口号可以从0到65535,通常将它分为三类:
公认端口(Well Known Ports):从0到1023,它们紧密绑定(Binding)一些服务。
注册端口(Registered Ports):从1024到49151。它们松散地绑定一些服务。你可以使用这些端口
动态和/或私有端口(Dynamic and/or Private Ports):从49152到65535。理论上,不应为服务分配这些端口。
下面介绍一些常用的应用程序所绑定的端口
端口 程序
22 ssh 安全 Shell(SSH)服务
23 是Telnet
25 smtp 简单邮件传输协议(SMTP),用于发送邮件
80 是HTTP
110 pop3 邮局协议版本,用于接收邮件
16.2URL类统一资源定位和Inetaddress类简介
1、主机名解析
前面讲过IP地址是唯一标识一台计算机,但是我们也可以使用主机名访问。另外,我们平时上网时就是访问另外一台计算机提供的服务,但是我们在浏览器上面输入的确不是IP地址而是域名,因为IP地址是一些无意义的数字,比较难记忆,所以才会出现域名这个技术,但是IP地址依然是计算机的唯一标识,所以我们就需要把域名或者主机名解析成IP地址,才能定位计算机。
域名或者主机名到IP地址的解析通过使用本地机器配置信息和网络命名服务(如域名系统(Domain Name System,DNS)来实现。对于任何主机名称,都返回其相应的 IP 地址。反向名称解析意味着对于任何IP地址,都返回与IP地址关联的主机。
InetAddress 类提供将主机名解析为其 IP 地址(或反之)的方法。常用方法如下:
byte[] getAddress()
返回此 InetAddress 对象的原始 IP 地址。
InetAddress[] getAllByName(String host)
在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组。
InetAddress getByAddress(byte[] addr)
在给定原始 IP 地址的情况下,返回 InetAddress 对象。
InetAddress getByAddress(String host, byte[] addr)
根据提供的主机名和 IP 地址创建 InetAddress。
InetAddress getByName(String host)
在给定主机名的情况下确定主机的 IP 地址。
String getCanonicalHostName()
获取此 IP 地址的完全限定域名。
String getHostAddress()
返回 IP 地址字符串(以文本表现形式)。
String getHostName()
获取此 IP 地址的主机名。
static InetAddress getLocalHost()
返回本地主机。
2、示例代码:
我们想知道一下百度服务器的IP地址,实现代码如下:
public static void main(String[] args) throws IOException {
// 互联网协议 (IP) 地址
InetAddress address = InetAddress.getByName("www.baidu.com");
System.out.println("(IP) 地址:" + address.getHostAddress());
System.out.println(" 地址:" + address.getHostName());
// localhost 192.168.11.144 127.0.0.1
InetAddress[] addresses = InetAddress.getAllByName("www.baidu.com");
for (int i = 0; i < addresses.length; i++) {
System.out.println("(IP) 地址" + addresses[i].getHostAddress());
}
}
打印后我们就知道百度服务器的IP地址是多少,运行结果如下:
二、URL类统一资源定位
1、简介
URL(Uniform Resource Locator)----统一资源定位器,表示Internet上某一资源的地址。java.net.URL类就是代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。比如新浪的一个新闻的定位:
http://finance.sina.com.cn/china/20131119/000617358603.shtml
通常,URL 可分成几个部分。上面的 URL 示例指示使用的协议为 http (超文本传输协议)并且该信息驻留在一台名为 finance.sina.com.cn的主机上。主机上的信息名称为 china/20131119/000617358603.shtml,URL 的这一部分称为路径部分,主机上此名称的准确含义取决于协议和主机。该信息一般存储在文件中,但可以随时生成。该 。
URL可选择指定一个“端口”,它是用于建立到远程主机TCP连接的端口号。如果未指定该端口号,则使用协议默认的端口。例如,http 协议的默认端口为80。
应用程序也可以指定一个“相对 URL”,它只包含到达相对于另一个 URL 的资源的足够信息。HTML 页面中经常使用相对 URL。例如,假设 URL 的内容是:
http://java.sun.com/index.html
其中包含的相对 URL:FAQ.html
为以下形式的缩写:http://java.sun.com/FAQ.html
相对 URL 不需要指定 URL 的所有组成部分。如果缺少协议、主机名称或端口号,这些值将从完整指定的 URL 中继承。但是,必须指定文件部分。可选的片段部分不继承。
具体内容大家可以参考JDK文档。
2、示例代码
把新浪网站下载下来,在控制台显示
public static void main(String[] args) throws IOException { URL url = new URL( "http://www.sina.com/"); BufferedReader br = new BufferedReader(new InputStreamReader( url.openStream())); String temp=br.readLine(); while(temp!=null){ System.out.println(temp); temp=br.readLine(); } br.close(); }
有关网络的更是内容,我们在后面学习android的网络通讯是讲解,这里就不详细讲解了。下面我们学习使用socket进行网络通信。
16.3socket的通讯
套接字(Socket)表示一个系统的IP地址和端口号的结合,是两台机器间通信的端点,用来处理两个流对象,通讯方式抽象成为流的方式。
通讯的两台计算机,一台担任服务器,一台担任客户机,服务器监听客户机是否连接。java.net.ServerSocket和java.net.Socket两个类用于建立一个双边的通信。ServerSocket类实现服务器,等待来自客户端的连接;Socket连接到一个服务器端,担任客户机。
创建TCP Socket需要的四个信息:
本地系统的IP
本地应用程序使用的TCP端口号
服务器系统的IP
服务器应用程序相应的TCP端口号
1、ServerSocket类
ServerSocket类用于侦听一个客户端的Socket连接,如果没有连接,它将一直等待。ServerSocket构造方法介绍如下:
ServerSocket(int port):用指定的端口port来创建一个侦听Socket,
ServerSocket(int port,int backlog):加上一个用来改变连接队列长度的参数backlog。
ServerSocket(int port,int backlog,InetAddress localAddr):在机器存在多个IP地址的情况下,允许通过localAddr这个参数来指定侦听的IP地址。
常用方法:
Socket accept():等待客户机的连接,并返回对应的Socket。
close():关闭连接。
bind(SocketAddress endpoint):将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
bind(SocketAddress endpoint, int backlog):将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
2、Socket类
Socket类常用构造器:
Socket(String host, int port):创建一个流套接字并将其连接到指定主机上的指定端口号。
Socket常用方法:
getInputStream():返回此套接字的输入流。
getOutputStream():返回此套接字的输出流。
close():关闭此套接字。
getLocalAddress():获取套接字绑定的本地地址。
getLocalPort():返回此套接字绑定到的本地端口。
二、示例代码
1、服务器端代码。新建一个Server类,实现代码如下:
/**
* 服务器
*
* @author Administrator
*
*/
public class Server {
public static void main(String[] args) throws IOException {
// 构造服务器端的soucket,监听端口
ServerSocket serverSocket = new ServerSocket(6001);
System.out.println("服务器启动,等待客户端的链接...");
// 程序在此定下来,等待客户端的链接
Socket socket = serverSocket.accept();
System.out.println("地址:"+socket.getLocalAddress());
// 发送一条信息给客户端
PrintWriter pw = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())));
pw.println("hi , 我是服务器端!!!");
pw.flush();
// 接受客户端端发送的信息
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
String temp=in.readLine();
System.out.println("客户端发来的信息:"+temp);
pw.close();
in.close();
socket.close();
serverSocket.close();
}
}
该程序运行到accept会停下来,等待客户机的连接,有客户机连接后,程序就会往下运行,先给客户及发送一条信息,然后再获得客户机发送过来的信息。最后关闭所有资源
2、客户端代码。客户机相对比较简单,就是连接服务器,然后接受服务器的信息,并向服务器发送一条信息。大家在运行我们这段代码时,需要把IP地址换成你电脑的IP地址。实现代码如下:
public class Client {
public static void main(String[] args) throws IOException {
// 指定ip和端口
Socket socket = new Socket(InetAddress.getByName("192.168.11.144"),
6001);
// 接受服务器发来的信息
BufferedReader br = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
System.out.println("服务端发来的信息:" + br.readLine());
// 发送一条信息给服务器
PrintWriter pw = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())));
pw.println("我是客户端");
pw.flush();
pw.close();
br.close();
socket.close();
}
}
3、测试
如果在MyEclipse的控制台测试不够直观的话,你也可以在Dos控制台中测试。先把这两个文件复制到D:盘中,使用javac命名编译成为字节码。
1、在运行中输入cmd,打开DOS控制台,编译源码。
2、先运行服务类。
3、再次在运行中输入cmd,打开另外一个Dos控制,运行客户机类。
两个控制台之间使用Socket实现了通讯,如果你有两台计算机也可以在两台计算机之间实现通讯。
三、实例
把客户机C:/abc.txt文本通过socket发送给服务机,并保存在服务机的D:盘中。
1、服务器端
public class FileServer { public static void main(String[] args) throws IOException { BufferedWriter bw = new BufferedWriter(new FileWriter("d://abc.txt")); // 构造服务器端的soucket,监听端口 ServerSocket serverSocket = new ServerSocket(6001); System.out.println("服务器启动,等待客户端的链接..."); // 程序在此定下来,等待客户端的链接 Socket socket = serverSocket.accept(); // 从客户端读取信息 BufferedReader in = new BufferedReader(new InputStreamReader( socket.getInputStream())); String temp = in.readLine(); while (temp != null) { System.out.println("客户端发来的信息:" + temp); // 写入硬盘 bw.write(temp + "\r\n"); temp = in.readLine(); } in.close(); bw.flush(); bw.close(); socket.close(); serverSocket.close(); } }
2、客户端
public class FileClient { public static void main(String[] args) throws UnknownHostException, IOException { // 读取硬盘文件 BufferedReader br = new BufferedReader(new FileReader("c://abc.txt")); // 把文件写到服务器 // 指定ip和端口 Socket socket = new Socket(InetAddress.getByName("192.168.11.144"), 6001); // 发送一条信息给服务器 PrintWriter pw = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream()))); String temp = br.readLine(); while (temp != null) { pw.println(temp); temp = br.readLine(); } pw.close(); socket.close(); } }
你可以在两台电脑之间运行,记得修改客户端的IP地址就可以了。当然你也可以只在本机上面测试,但是现在不同我们之前学习IO时候的简单的复制,而是通过网络传输了。
16.4使用多线程监听多客户端
上一节的中我们只是实现了一次通讯,下面我们要做的例子可以允许多个客户机,多次发送信息给服务器。
一、思路
要实现这个功能,服务器需要不断的等待新的客户机连接,每一个新的客户机连接,我们就启动一个新的线程来维护与当前的客户机的socket连接,客户输入“bye”是,这个客户就退出。如果你忘记了线程,最好先回去复习一下。思路图如下:
二、实现代码
1、与客户端对应的线程类。实现代码如下:
/**
* 与每一个客户端对应的线程
*
* @author Administrator
*
*/
public class SocketThread extends Thread {
private Socket socket;//对应的socket
private String name;
private BufferedReader in;
private PrintWriter pw;
public SocketThread(String name, Socket socket) {
this.name = name;
this.socket = socket;
try {
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
pw.println("欢迎:"+name);
pw.flush();
try {
String temp = in.readLine();
while (true) {
System.out.println("客户端发来的信息:" + temp);
temp = in.readLine();
if (temp.equals("bye")) {
break;
}
}
in.close();
pw.flush();
pw.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2、服务端代码。
public class Server {
public static void main(String[] args) throws IOException {
// 构造服务器端的soucket,监听端口
ServerSocket serverSocket = new ServerSocket(6001);
System.out.println("服务器启动,等待客户端的链接...");
// 程序在此定下来,等待客户端的链接
int i=0;
//不断等待客户端的链接
while(true){
Socket socket = serverSocket.accept();
i++;
//启动一个线程,
SocketThread socketThread=new SocketThread
(socket.getInetAddress().getHostName()+":"+i, socket);
socketThread.start();
}
}
}
3、客户端代码。
public class Client {
public static void main(String[] args) throws UnknownHostException,
IOException {
// 指定ip和端口
Socket socket = new Socket(InetAddress.getByName("192.168.11.144"),
6001);
// 接受服务器发来的信息
BufferedReader br = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
System.out.println("服务端发来的信息:" + br.readLine());
// 发送一条信息给服务器
PrintWriter pw = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())));
pw.println("liu");
pw.flush();
Scanner scanner = new Scanner(System.in);
String temp = null;
while (true) {
System.out.print("说话:");
temp = scanner.next();
pw.println(temp);
pw.flush();
if (temp.equals("bye")) {
break;
}
}
pw.close();
socket.close();
}
}
4、测试。
把所有的类复制到D:盘中,使用Dos控制台,服务器使用一个控制台,每一个客户端一个Dos控制台。
也是先编译,然后启动服务类:
这时候你可以多打开几个Dos控制台运行客户机类。
相关推荐
- 给学校公司同学出的一些题目---java, jquery, spring, springmvc, mybatis, 网络编程, linux, mysql(持续更新)
- python笔记系列-day22:网络编程socket
- java网络编程 url
- Java---net(网络编程)---理论
- 不是太细的java自学笔记进阶篇8(p619-661)(java网络编程,反射机制)
- JAVA基础--编程工具Eclipse安装及使用
- 【Java基础】(五-中)Java的编程工具eclipse——初识eclipse
- Java基础编程(四)-基础编程2
- 学习算法,你需要掌握这些编程基础(包含JAVA和C++)
- 10.python网络编程(socket server 实现并发 part 2)
- 工作5年的阿里Java程序员分享从业心得总结与面试笔记分享
- (转载)socket编程原理