Java网络详解
Java网络基本概念
网络基础知识
1、计算机网络形式多样,内容繁杂。网络上的计算机要互相通信,必须遵循一定的协议。目前使用最广泛的网络协议是Internet上所使用的TCP/IP协议
2、网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯。网络编程中有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输。在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机。而TCP层则提供面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。
3、目前较为流行的网络编程模型是客户机/服务器(C/S)结构。即通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提出申请。服务器一般作为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时自己继续监听服务端口,使后来的客户也能及时得到服务。
网络基本概念
1、IP地址:标识计算机等网络设备的网络地址,由四个8位的二进制数组成,中间以小数点分隔。
如:166.111.136.3 , 166.111.52.80
2、主机名(hostname):网络地址的助记名,按照域名进行分级管理。
如:www.tsinghua.edu.cn 、www.baidu.com
3、端口号(port number):网络通信时同一机器上的不同进程的标识。
如:80,21,23,25,端口号范围为0到65535,其中1~1024为系统保留的端口号
4、服务类型(service):网络的各种服务。
http, telnet, ftp, smtp
在Internet上IP地址和主机名是一一对应的,通过域名解析可以由主机名得到机器的IP,由于机器名更接近自然语言,容易记忆,所以使用比IP地址广泛,但是对机器而言只有IP地址才是有效的标识符。
通常一台主机上总是有很多个进程需要网络资源进行网络通讯。网络通讯的对象准确的讲不是主机,而应该是主机中运行的进程。这时候光有主机名或IP地址来标识这么多个进程显然是不够的。端口号就是为了在一台主机上提供更多的网络资源而采取得一种手段,也是TCP层提供的一种机制。只有通过主机名或IP地址和端口号的组合才能唯一的确定网络通讯中的对象:进程。
服务类型是在TCP层上面的应用层的概念。基于TCP/IP协议可以构建出各种复杂的应用,服务类型是那些已经被标准化了的应用,一般都是网络服务器(软件)。读者可以编写自己的基于网络的服务器,但都不能被称作标准的服务类型。
网络模型
网络参考模型:
网络不同层的协议:
传输协议:TCP、UDP
尽管TCP/IP协议的名称中只有TCP这个协议名,但是在TCP/IP的传输层同时存在TCP和UDP两个协议:
1、TCP是Tranfer Control Protocol的简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。
2、UDP是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
下面对这两种协议做简单比较:
1、使用UDP时,每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。对于TCP协议,由于它是一个面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中多了一个连接建立的时间。
2、使用UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。而TCP没有这方面的限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大量的数据。UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。而TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据。
TCP、UDP比较:
UDP
- 将数据及源和目的封装成数据包中,不需要建立连接
- 每个数据报的大小在限制在64k内
- 因无连接,是不可靠协议
- 不需要建立连接,速度快
UDP就像是在邮局邮递包裹。只管发送,不管对方能不能收到。
TCP
- 建立连接,形成传输数据的通道。
- 在连接中进行大数据量传输
- 通过三次握手完成连接,是可靠协议
- 必须建立连接,效率会稍低
TCP就像是打电话,必须接通之后才能说话。
Java网络编程
InetAddress
此类表示互联网协议 (IP) 地址。 IP 地址是 IP 使用的 32 位或 128 位无符号数字,它是一种低级协议,UDP 和 TCP 协议都是在它的基础上构建的。IP 地址的体系结构是由 RFC 790:Assigned Numbers等定义的。InetAddress 的实例包含 IP 地址,还可能包含相应的主机名(取决于它是否用主机名构造或者是否已执行反向主机名解析)。
public class IPDemo {
/**
* @param args
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException {
//获取本地主机IP地址对象。
InetAddress ip = InetAddress.getLocalHost();
//获取其他主机的IP地址对象。
InetAddress ip2 = InetAddress.getByName("119.75.218.70");
//通过指定主机名来创建IP地址对象
//InetAddress.getByName("chen-pc");
//打印IP地址字符串
System.out.println(ip.getHostAddress());
//打印IP地址的主机名字符串
System.out.println(ip.getHostName());
//通过主机名获取主机所有的IP地址
InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com");
for (InetAddress inet : allByName) {
System.out.println(inet.getHostAddress());
}
}
}
URI
统一资源标识符(Uniform Resource Identifier,URI)是一种采用特定语法标识一个资源的字符串。所标记的资源可能是服务器的一个文件,也可能是一个邮件地址、新闻信息、图书、人名、Internet主机或者其他任何内容。
URL
类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。
通常,URL 可分成几个部分。上面的 URL 示例指示使用的协议为 http (超文本传输协议)并且该信息驻留在一台名为 www.socs.uts.edu.au 的主机上。主机上的信息名称为 /MosaicDocs-old/url-primer.html。主机上此名称的准确含义取决于协议和主机。该信息一般存储在文件中,但可以随时生成。该 URL 的这一部分称为路径 部分。
URL和URI的区别:
URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。而URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。也就是说,URI是以一种抽象的,高层次概念定义统一资源标识,而URL则是具体的资源标识的方式。URL是一种URI。
在Java的URI中,一个URI实例可以代表绝对的,也可以是相对的,只要它符合URI的语法规则。而URL类则不仅符合语义,还包含了定位该资源的信息,因此它不能是相对的,schema必须被指定。
程序方面:URI 类在某些特定情况下对其组成字段执行转义。建议使用 URI 管理 URL 的编码和解码,并使用 toURI() 和 URI.toURL() 实现这两个类之间的转换。
String urlString = "http://192.168.21.77:8080/swp/mainPage?aa=11&bb%3D22";
URI uri = URI.create(urlString);
System.out.println(uri.getPath());
System.out.println(uri.getQuery());//解码
URL url2 = new URL(urlString);
System.out.println(url2.getQuery());//不解码
解析一个URL: (URI的解析类似)
一个URL对象生成后,其属性是不能被改变的,但是我们可以通过类URL所提供的方法来获取这些属性:
/**
* 解析URL(URI解析类似)
*/
public class ParseURL {
public static void main(String[] args) throws Exception {
//指定URL
URL Aurl = new URL("http://java.sun.com:80/docs/books/");
URL tuto = new URL(Aurl, "tutorial.intro.html#DOWNLOADING");
//获取该URL的协议名
System.out.println("protocol=" + tuto.getProtocol());
//获取该URL的主机名
System.out.println("host =" + tuto.getHost());
//获取该URL的文件名
System.out.println("filename=" + tuto.getFile());
//获取该URL的端口号,如果没有设置端口,返回-1
System.out.println("port=" + tuto.getPort());
//获得该URL的锚
System.out.println("ref=" + tuto.getRef());
//获取该URL的查询信息
System.out.println("query=" + tuto.getQuery());
//获取该URL的路径
System.out.println("path=" + tuto.getPath());
//获得使用者的信息
System.out.println("UserInfo=" + tuto.getUserInfo());
//获取该URL的权限信息
System.out.println("Authority=" + tuto.getAuthority());
}
}
Socket
此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
套接字的实际工作由 SocketImpl 类的实例执行。应用程序通过更改创建套接字实现的套接字工厂可以配置它自身,以创建适合本地防火墙的套接字。
- Socket就是为网络服务提供的一种机制。
- 通信的两端都有Socket。
- 网络通信其实就是Socket间的通信。
- 数据在两个Socket间通过IO传输。
我们说的网络编程其实就是socket编程
UDP通信
通信过程图示:
UDP是面向无连接的:
一. UDP协议定义
UDP协议的全称是用户数据报,在网络中它与TCP协议一样用于处理数据包。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据报分组、组装和不能对数据包的排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。
二. 使用UDP的原因
它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。比如我们聊天用的ICQ和OICQ就是使用的UDP协议。在选择使用协议的时候,选择UDP必须要谨慎。在网络质量令人不十分满意的环境下,UDP协议数据包丢失会比较严重。
UDP客户端编程涉及的步骤是4个部分:
使用到的类:DatagramSocket与DatagramPacket
- 获取socket对象
- 对数据进行封包
- 通过socket对象把数据包发送出去
- 把连接关闭
注意:
- 在发送端,要在数据包对象中明确目的地IP及端口。
- 在接收端,要指定监听的端口。
使用UDP协议建立信息发送端:
/**
* 通过udp协议发送数据
*/
public class UdpSendDemo {
/**
* 1:获取socket对象
* 2:对数据进行封包
* 3:通过socket对象把数据包发送出去
* 4:把连接关闭
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//1:获取对象
DatagramSocket ds = new DatagramSocket();
//2:封包
byte[] buf = "UDP ......!".getBytes();
DatagramPacket p = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.3.255"), 3000);
//3.发送数据包
ds.send(p);
//4.关闭连接
ds.close();
}
}
UDP服务端编程涉及的步骤是4个部分:
- 获取socket连接(需要指定监听的端口)
- 通过receive方法接收数据包
- 解包,获取数据包中的内容
- 关闭连接
使用UDP建立信息接收端:
/**
* UDP接收端代码
*/
public class UdpReceiveDemo {
/**
* 1:获取socket连接(需要指定监听的端口)
* 2:通过receive方法接收数据包
* 3:解包,获取数据包中的内容
* 4:关闭连接
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//1:获取连接
DatagramSocket ds = new DatagramSocket(3000);
while (true) {
//2:接收数据
byte[] buf = new byte[1024];
DatagramPacket p = new DatagramPacket(buf, 0, buf.length);
ds.receive(p);
//3:获取数据
String value = new String(p.getData(), 0, p.getLength());
System.out.println(value + p.getAddress().getHostAddress());
}
//4:关闭连接
//ds.close();
}
}
UDP信息交互:聊天室程序(使用多线程)
/**
* 聊天室程序,使用多线程
*/
public class ChatDemo
{
public static void main(String[] args) throws Exception
{
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receSocket = new DatagramSocket(10002);
//启动socket客户端,发送数据
new Thread(new Send(sendSocket)).start();
//启动socket服务端,接收数据
new Thread(new Rece(receSocket)).start();
}
}
//发送端
class Send implements Runnable
{
private DatagramSocket ds;
//创建客户端socket发送对象
public Send(DatagramSocket ds)
{
this.ds = ds;
}
//重写Runnable接口中的run()方法
public void run()
{
try
{
//用户输入作为发送的数据
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bufr.readLine())!=null)
{
//字符串转化为字节数组
byte[] buf = line.getBytes();
//封装发送的数据包,其中255为广播地址
DatagramPacket dp =
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10002);
ds.send(dp);
//设置用户输入终止标记
if("886".equals(line))
break;
}
}
catch (Exception e)
{
throw new RuntimeException("发送端失败");
}
}
}
//接收端
class Rece implements Runnable
{
private DatagramSocket ds;
//1,创建接收的socket对象
public Rece(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try
{
while(true)
{
// 2,创建数据包
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
// 3,使用接收方法将数据存储到数据包中。
ds.receive(dp);// 阻塞式的。
// 4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
if("886".equals(data))
{
System.out.println(ip+"....离开聊天室");
break;
}
System.out.println(ip+":"+data);
}
}
catch (Exception e)
{
throw new RuntimeException("接收端失败");
}
}
}
TCP通信
通信过程图示:
- TCP是面向连接的协议,也就是说,在双方都确认连接的情况下,才会继续发送数据。
- TCP一般用于文件传输(FTP HTTP 对数据准确性要求高,速度可以相对慢),发送或接收邮件(POP IMAP SMTP 对数据准确性要求高,非紧急应用),远程登录(TELNET SSH 对数据准确性有一定要求,有连接的概念)等等;
三步握手的过程如下:
第一步,客户端发送一个连接请求到服务器,如果没有收到响应或者服务器返回失败则客户端返回失败,不能正确连接。
第二步,服务器端在接收到连接请求后,发回一个同意请求连接,返回给客户端,并且等待客户端的第三次回应,如果没有回应,服务器端关闭连接。
第三步,客户端端收到服务器的同意请求后,再次发送一个同意连接。至此连接建立。剩下的就是TCP数据交互过程。
TCP服务端编程涉及的步骤是4个部分:
- 使用到的类Socket和ServerSocket
- 建立客户端和服务器端
- 建立连接后,通过Socket中的IO流进行数据的传输
- 关闭socket
注意:
- 通过Socket建立对象并指定要连接的服务端主机以及端口。
- 建立服务端需要监听一个端口
使用TCP建立客户端:
/**
* tcp发送端
*/
public class TcpSendDemo {
/**
* 1:创建socker客户端,需要连接到接收端
* 2:获取这个socket的输出流
* 3:通过输出流给其他服务器发送数据
* 4:关键连接
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//1:获取socker对象
Socket socket = new Socket("192.168.3.62",4000);
//2:获取输出流
OutputStream outputStream = socket.getOutputStream();
//3:通过输出流写数据
outputStream.write("TCP hehe.....".getBytes());
//4:关闭连接
socket.close();
}
}
使用TCP建立服务端:
//接收端
public class TcpReceiveDemo {
/**
* 1:创建一个socket服务端,需要监听指定端口
* 2:通过这个服务端对象可以获取到给指定端口发送数据的socket客户端对象
* 3:通过socket对象获取具体的读取流
* 4:通过读取流获取数据
* 5:关闭连接
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//1:获取serversocket
ServerSocket serverSocket = new ServerSocket(4000);
//2:获取客户端的socket对象
Socket socket = serverSocket.accept();//也是一个阻塞方法,获取socket客户端对象
//3:获取socket的输入流
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
//4:读取数据
int read = in.read(bytes);
String value = new String(bytes, 0, read);
System.out.println(value);
//5:关闭连接
socket.close();
serverSocket.close();
}
}
使用TCP建立交互方式:
/**
* tcp发送端
*/
public class TcpSendDemo {
/**
* 1:创建socker客户端,需要连接到接收端
* 2:获取这个socket的输出流
* 3:通过输出流给其他服务器发送数据
* 4:关键连接
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//1:获取socker对象
Socket socket = new Socket("192.168.3.62",4000);
//2:获取输出流
OutputStream out = socket.getOutputStream();
//3:通过输出流写数据
out.write("TCP hehe.....".getBytes());
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
int read = in.read(bytes);
String result = new String(bytes,0,read);
System.out.println(System.currentTimeMillis()+"收到服务端发送的数据:----->>>>>"+result);
//4:关闭连接
socket.close();
}
}
//接收端
public class TcpReceiveDemo {
/**
* 1:创建一个socket服务端,需要监听指定端口
* 2:通过这个服务端对象可以获取到给指定端口发送数据的socket客户端对象
* 3:通过socket对象获取具体的读取流
* 4:通过读取流获取数据
* 5:关闭连接
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//1:获取serversocket
ServerSocket serverSocket = new ServerSocket(4000);
//2:获取客户端的socket对象
Socket socket = serverSocket.accept();//也是一个阻塞方法,获取socket客户端对象
//3:获取socket的输入流
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
//4:读取数据
int read = in.read(bytes);
String value = new String(bytes, 0, read);
System.out.println(value);
OutputStream out = socket.getOutputStream();
out.write(("收到TCP客户端发的数据了。"+System.currentTimeMillis()).getBytes());
//5:关闭连接
socket.close();
serverSocket.close();
}
}
网络编程小程序
TCP创建英文大写转化服务器:
/**
* TCP发送端(发送从命令行读入的数据)
*/
public class TransClient {
/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
//1,创建socket客户端对象。
Socket s = new Socket("192.168.0.163", 10004);
//2,获取键盘录入。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//3,socket输出流。
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
//4,socket输入流,读取服务端返回的大写数据
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while ((line = bufr.readLine()) != null) {
if ("over".equals(line)) break;
out.println(line);
//读取服务端发回的一行大写数。
String upperStr = bufIn.readLine();
System.out.println(upperStr);
}
s.close();
}
}
/**
* TCP服务端(接收从客户端发来的数据,并转大写返回)
*/
public class TransServer {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//1,创建ServerSocket对象
ServerSocket ss = new ServerSocket(10004);
//2,获取socket对象。
Socket s = ss.accept();
//获取ip.
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "......connected");
//3,获取socket读取流,并装饰。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
//4,获取socket的输出流,并装饰。
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
String line = null;
while ((line = bufIn.readLine()) != null) {
System.out.println(line);
//把收到的数据转大写并发送回客户端
out.println(line.toUpperCase());
}
//关闭流
s.close();
ss.close();
}
}
客户端上传文本文件到服务端:
//文件发送端
public class UploadClient {
/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("上传文件。。。。。。");
File file = new File("d:\\client.txt");
System.out.println(file.exists());
//1,创建客户端socket对象
Socket s = new Socket("192.168.0.163", 10005);
//2,创建高效字符流读取对象
BufferedReader bufr = new BufferedReader(new FileReader(file));
//3,创建打印流对象
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
String line = null;
while ((line = bufr.readLine()) != null) {
out.println(line);
}
//告诉服务端,客户端写完了。
s.shutdownOutput();
out.println("发送结束");
//4,创建接收的字符流对象
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = bufIn.readLine();
System.out.println(str);
bufr.close();
s.close();
}
}
//文件接收端
public class UploadServer {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
System.out.println("等待文件上传。。。。。。。。。");
//1,创建服务端ServerSocket对象
ServerSocket ss = new ServerSocket(10005);
//2, 通过服务端对象的accept()对象接收一个请求连接的客户端对象
Socket s = ss.accept();
//打印连接的客户端信息
System.out.println(s.getInetAddress().getHostAddress() + ".....connected");
//3,获取客户端发送来的数据
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
//4,创建高效字符流写出对象
BufferedWriter bufw = new BufferedWriter(new FileWriter("d:\\server.txt"));
String line = null;
while ((line = bufIn.readLine()) != null) {
//写入读取的字符
bufw.write(line);
//新起一行
bufw.newLine();
//刷新缓冲区
bufw.flush();
}
//返回信息给客户端
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println("上传成功");
//关闭流
bufw.close();
//关闭socket
s.close();
ss.close();
}
}
TCP图片上传:
//图片上传客户端
public class UploadPicClient {
/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
//1,创建客户端socket。
Socket s = new Socket("192.168.31.226", 10006);
//2,读取客户端要上传的图片文件。
FileInputStream fis = new FileInputStream("D:\\tmp.jpg");
//3,获取socket输出流,将读到图片数据发送给服务端。
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
//告诉服务端数据发送完毕。让服务端停止读取。
s.shutdownOutput();
//读取服务端发回的内容。
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int lenIn = in.read(buf);
String text = new String(buf, 0, lenIn);
System.out.println(text);
fis.close();
s.close();
}
}
//图片上传服务端
public class UploadPicServer {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//创建tcp的socket服务端。
ServerSocket ss = new ServerSocket(10006);
while (true) {
Socket s = ss.accept();
new Thread(new UploadTask(s)).start();
}
//获取客户端。
// ss.close();
}
}
class UploadTask implements Runnable {
private static final int SIZE = 1024 * 1024 * 2;
private Socket s;
public UploadTask(Socket s) throws IOException {
this.s = s;
}
@Override
public void run() {
int count = 0;
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + ".....connected");
try {
// 读取客户端发来的数据。
InputStream in = s.getInputStream();
// 将读取到数据存储到一个文件中。
File dir = new File("D:\\pic");
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir, ip + ".jpg");
//如果文件已经存在于服务端
while (file.exists()) {
file = new File(dir, ip + "(" + (++count) + ").jpg");
}
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
//判断文件大小
if (file.length() > SIZE) {
System.out.println(ip + "文件体积过大");
fos.close();
s.close();
System.out.println(ip + "...." + file.delete());
return;
}
}
// 获取socket输出流,将上传成功字样发给客户端。
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
模拟浏览器请求Tomcat:
public class MyBrowser {
/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
Socket s = new Socket("192.168.31.226", 8080);
//模拟浏览器,给tomcat服务端发送符合http协议的请求消息。
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
//需要打开Tomcat服务器,并且在网站根目录添加 myweb/1.html
out.println("GET /myweb/1.html HTTP/1.1");
out.println("Accept: */*");
out.println("Host: 192.168.31.226:8080");
out.println("Connection: close");
out.println();
out.println();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String str = new String(buf, 0, len);
System.out.println(str);
s.close();
}
}
模拟Tomcat服务器:
/**
* 模拟Tomcat服务器
*/
public class MyTomcat {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9090);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress() + ".....connected");
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf, 0, len);
System.out.println(text);
//给客户端一个反馈信息。
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println("<font color='red' size='7'>欢迎光临</font>");
s.close();
ss.close();
}
}
TCP扫描本网段是否有服务端:
客户端在0~255内扫描是否有服务端:
public class ClientTest {
public static void main(String[] args) {
Thread thread = new Thread(new ClientConnet());
thread.start();
}
}
//实现Runnable接口
class ClientConnet implements Runnable {
@Override
public void run() {
String str = "";
try {
str = getHostPart();
} catch (UnknownHostException e) {
e.printStackTrace();
}
//切割IP地址 eg: 192.168.241.
int end = str.lastIndexOf(".");
String substring = str.substring(0, end + 1);
for (int i = 0; i < 255; i++) {
Socket socket = null;
//拼接IP地址如192.168.241. + 0 --> 192.168.241.0
String ipStr = substring + i;
try {
//创建socket
SocketAddress socketAddress = new InetSocketAddress(ipStr, 4000);
socket = new Socket();
System.out.println(ipStr);
//设置socket连接超时时间
socket.connect(socketAddress, 100);
System.out.println("Connected...");
//写出流
OutputStream outputStream = socket.getOutputStream();
//如果连接上,则循环打印信息给服务端
while (true) {
String writeInfo = "This is : " + socket.getLocalAddress().toString();
outputStream.write(writeInfo.getBytes());
}
} catch (Exception e) {
//e.printStackTrace();
} finally {
if (socket != null) {
try {
//关闭socket
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
System.out.println("此局域网无主机。。。。");
}
//获取IP地址
public String getHostPart() throws UnknownHostException {
InetAddress localHost = InetAddress.getLocalHost();
String hostAddress = localHost.getHostAddress();
return hostAddress;
}
}
/**
* 服务端
*/
public class ServerTest {
public static void main(String[] args) throws IOException {
//创建服务端socket
ServerSocket serverSocket = new ServerSocket(4000);
//通过服务端ServerSocket的accept()方法,返回一个客户端socket对象
Socket accept = serverSocket.accept();
//通过接收的客户端socket对象读入数据
InputStream inInfo = accept.getInputStream();
//循环打印接收的数据
while (true) {
byte[] buf = new byte[1024];
int len = inInfo.read(buf);
System.out.println(new String(buf, 0, len));
}
}
}
端口占用情况扫描:
端口号范围为0到65535,其中0到1023的端口号一般分配给一些服务。比如FTP服务(21),SMTP(25)服务,HTTP(25)服务,135分配给RPC(远程过程调用)等;从1024到65535的端口号供用户自定义的服务使用。
//通过UDP扫描本机已被占用的端口
public class NetTest {
public static void main(String args[]) {
for (int port = 1024; port <= 65535; port++) {
try {
DatagramSocket server = new DatagramSocket(port);
server.close();
} catch (SocketException e) {
System.out.println("there is a server in port " + port + ".");
}
}
}
}