一、概述
1、网络模型:OSI参考模型和TCP/IP参考模型。
2、网络通信要素:IP地址、端口号、传输协议。
1)IP地址:
1、它是网络中的设备标识。
2、不易记忆,可用主机名表示,两者存在映射关系。
3、本机回环地址:127.0.0.1,主机名为:localhost。
2)端口号:
1、逻辑端口:用于标识进程的逻辑地址,不同进程的标识;
2、有效端口:0~65535,其中0~1024系统使用或保留端口。
二、常见协议(UDP、TCP)
一)UDP的特点:
1)面向无连接。
2)数据会被封包,在64K内。
3)不可靠,因为无连接,所以不可靠。
4)速度快,因为不需要连接。
例如:聊天的时候就是UDP的,还有视频会议,桌面共享等。
二)TCP的特点:
1)建立连接,形成传输数据的通道。
2)在连接中进行大数据量传输。
3)通过三次握手完成连接。是可靠的协议。
4)必须建立连接,但是效率稍低。
例如:打电话就是TCP的。
UDP就相当于对讲机,TCP相当于电话。
下载就是TCP的因为不能丢数据,聊天就是UDP的。
三)UDP传输的步骤:
1)UDP的发送端:
1、建立udp的socket服务,创建对象时如果没有明确端口,系统会自动分配一个未被使用的端口。
2、明确要发送的具体数据。
3、将数据封装成了数据包。
4、用socket服务的send方法将数据包发送出去。
5、关闭资源。
2)UDP的接收端:
1、创建udp的socket服务,必须要明确一个端口,作用在于,只有发送到这个端口的数据才是这个接收端可以处理的数据。
2、定义数据包,用于存储接收到数据。
3、通过socket服务的接收方法将收到的数据存储到数据包中。
4、通过数据包的方法获取数据包中的具体数据内容,比如ip、端口、数据等等。
5、关闭资源。
示例1:
import java.net.*;
class UdpSend
{
public static void main(String[] args) throws Exception
{
//1,创建udp服务。通过DatagramSocket对象。
DatagramSocket ds = new DatagramSocket(8888);
//2,确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress address, int port)
byte[] buf = "udp ge men lai le ".getBytes();
DatagramPacket dp =
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.254"),10000);
//3,通过socket服务,将已有的数据包发送出去。通过send方法。
ds.send(dp);
//4,关闭资源。
ds.close();
}
}
import java.net.*;
class UdpRece
{
public static void main(String[] args) throws Exception
{
//1,创建udp socket,建立端点。
DatagramSocket ds = new DatagramSocket(10000);
while(true)
{
//2,定义数据包。用于存储数据。
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3,通过服务的receive方法将收到数据存入数据包中。
ds.receive(dp);//阻塞式方法。
//4,通过数据包的方法获取其中的数据。
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(ip+"::"+data+"::"+port);
}
//5,关闭资源
//ds.close();
}
}
示例3:编写一个聊天程序。
四)TCP的两个端点:
一个是客户端,一个是服务端。
客户端:对应的对象,Socket。
服务端:对应的对象,ServerSocket。
五)TCP的传输步骤:
1)TCP客户端:
1、建立tcp的socket服务,最好明确具体的地址和端口。这个对象在创建时,就已经可以对指定ip和端口进行连接(三次握手)。
2、如果连接成功,就意味着通道建立了,socket流就已经产生了。只要获取到socket流中的读取流和写入流即可,只要通过getInputStream和getOutputStream就可以获取两个流对象。
3、关闭资源。
2)TCP服务端:
1、创建服务端socket服务,并监听一个端口。
2、服务端为了给客户端提供服务,获取客户端的内容,可以通过accept方法获取连接过来的客户端对象。
3、可以通过获取到的socket对象中的socket流和具体的客户端进行通讯。
4、如果通讯结束,关闭资源。
注意:要先关客户端,再关服务端。
三、
InetAddress
(java.net)
1、特点:无构造函数,可通过getLocalHost()方法获取InetAddress对象,此方法是静态的,返回此对象。
2、常用方法:
1) static | InetAddress getLocalHost() :返回本地主机。
2) static InetAddress getByName(String host):在给定主机名的情况下确定主机的 IP 地址。
3) String getHostAddress() : 返回 IP 地址字符串(以文本表现形式)。
4)String getHostName():获取此 IP 地址的主机名。
示例3:
ort java.net.*;
class InetDemo
ati
{
publi
void main(String[] args) throws Exception
{
//获取本机IP地址
.getLocalHost();
System.out.println(ia.to
InetAddress ia = InetAdd
ring());
//通过百度主机名获取其IP地址
一)Socket是什么?
就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。
二)DatagramSocket(java.net )
2)常用方法:void send(DatagramPacket p) :从此套接字发送数据报包。
三)DatagramPacket (java.net )
1、构造方法:
1) DatagramPacket(byte[] buf, int length) :构造 DatagramPacket,用来接收长度为 length 的数据包。
1)int getPort() :返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
五、TCP传输
一)概述:包括客户端和服务端,即Socket为客户端,ServerSocket为服务端。
二)Socket (java.net)
1、构造方法:
Socket(String host, int port) :创建一个流套接字并将其连接到指定主机上的指定端口号。2、常用方法:
1)OutputStream | getOutputStream() :返回此套接字的输出流。
3) void | shutdownInput() :此套接字的输入流置于“流的末尾”。
4)void | shutdownOutput():禁用此套接字的输出流。
三)ServerSocket ( java.net )
1、构造方法: ServerSocket(int port) :创建绑定到特定端口的服务器套接字。
2、常用方法:
1)Socket accept() :侦听并接受到此套接字的连接,将ServerSocket变成Socket。
2)InetAddress getInetAddress() :返回此服务器套接字的本地地址。
四)客户端:
在该对象建立时就可去连接指定主机,因为TCP是面向俩接的,所以在建立Socket服务时,就要有服务端存在,并连接成功,形成通路后,再通过该通道进行数据的传输。
步骤:
1)创建Socket服务,并指定要连接的主机端口。通路一建立,就会产生Socket流(包括输入流和输出流),通过方法获取。
2)为了发送数据,应获取Socket中的输出流,如果要接收服务端的反馈信息,需要获取Socket的输入流。
3)通过write()方法将信息写入到流中。
4)关闭Socket流资源。
示例:
import java.io.*;
import java.net.*;
class TcpClient//客户端
{
lic static void main(String[] args) throws Exception
{
pu
b
//创建客户端的socket服务。指定目的主机和端口
",10003);
//为了发送数据,应该获取socket流中的输出流。
Socket s = new Socket("127.0.0.
1
OutputStream out = s.getOutputStream();
s.close();
}
}
out.write("tcp ge men lai le ".getBytes());
五)服务端:
定义端连接数据,并存放指定地方,需监听一个端口。
步骤:
1)建立服务端的Socket服务,通过ServerSocet带端口参数的构造函数。
2)获取连接过来的客户对象,通过ServerSocket的accept()方法,此方法是阻塞式的,如果服务端没有连接到就会等待。
3)客户端若发来数据,则服务端要使用对应的客户端对象,并获取到该客户端对象的读取流发来的数据,并输出到指定目的地。
4)关闭服务端。一般服务端是常开的,因为在实际应用中,随时有客户端在请求连接和服务,所有这里需要定时关闭客户端对象流,避免某一个客户端长时间占用服务器端。
import java.io.*;
import java.net.*;
class TcpServer//服务端
{
lic static void main(String[] args) throws Exception
{
pu
b
//建立服务端socket服务。并监听一个端口。
cket(10003);
//通过accept方法获取连接过来的客户端对象。
ServerSocket ss = new ServerS
o
while(true)
{
ket s = ss.accept();
So
c
System.out.println(ip+".....connected");
//获取
String ip = s.getInetAddress().getHostAddress();
客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
InputStream in = s.getInputStream();
ntln(new String(buf,0,len));
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.pr
i
s.close();//关闭客户端.
}
//ss.close();
}
}
/*
客户端。
1,服务端点。
2,读取客户端已有的图片数据。
3,通过socket 输出流将数据发给服务端。
4,读取服务端反馈信息。
5,关闭。
*;
*/
import java.io
.
import java.net.*;
public static voi
class PicClient
{
rows Exception
{
//对传进来的文件进行多重判断
d main(String[] args)t
h
if(args.length!=1)
{
的图片");
return ;
}
File fi
System.out.println("请选择一个jpg格
式le = new File(args[0]);
if(!(file.exists() && file.isFile()))
}
{
System.out.println("该文件有问题,要么补存在,要么不是文件");
return ;
if(!file.getName().endsWith(".jpg"))
{
;
}
if(file.length()>1024*102
System.out.println("图片格式错误,请重新选择");
return
4*5)
{
System.out.println("文件过大,没安好心");
return ;
}
//建立字节流和文件相关联
FileInp
//建立Socket服务,往服务端发送数据
Socket s = new Socket("127.0.0.1",10007);
utStream fis = new FileInputStream(file);
//使用Socket输出方法网服务端写出数据
];
int len = 0;
while((len=fi
OutputStream out = s.getOutputStream();
byte[] buf = new byte[102
4s.read(buf))!=-1)
{
out.write(buf,0,len);
}
//告诉服务端数据已写完
s.shutdownOutput();
int num = in.read(bufI
//使用Socket输出方法网服务端接收数据
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
n);
System.out.println(new String(bufIn,0,num));
fis.close();
s.close();
}
}
/*
服务端
那么为了可以让多个客户端同时并发访问服务端。
那么服务端最好就是将每个客户
这个服务端有个局限性。当A客户端连接上以后。被服务端获取到。服务端执行具体流程。
这时B客户端连接,只有等待。
因为服务端还没有处理完A客户端的请求,还有循环回来执行下次accept方法。所以
暂时获取不到B客户端对象。
端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。
如何定义线程呢?
只要明确了每一个客户端要在服务端执行的代码即可。将该代码存入run方法中。
*/
class PicThread implements Runnable
{
//传进来的客户端
//获取客户端连进来的IP
private Socket s;
PicThread(Socket s)
{
this.s = s;
}
//对现场的Run方法
public void run()
{
//定义计数器,为了不让存入的文件相同
int count = 1;
String ip = s.getInetAddress().getHostAddress();
try
{
//打印客户端IP
System.out.println(ip+"....connected");
//接收客户端传来的图片
r,ip+"("+(count)+")"+".jpg");
//如
InputStream in = s.getInputStream();
//创建了路径.并存入格式比如 127.0.0.1(1).jpg
File dir = new File("d:\\pic");
File file = new File(d
i果文件存在的话就用while循环判断文件是否存在.知道不存在添加
while(file.exists())
file = new File(dir,ip+"("+(count++)+")"+".jpg");
//输出
FileOutputStream fos = new FileOutputStream(file);
ream();
out.write("上传成功".
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1)
{
fos.write(buf,0,len);
}
//告诉客户端上传成功
OutputStream out = s.getOutputS
tgetBytes());
fos.close();
s.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"上传失败");
}
}
}
class PicServer//服务端
{
.accept();
//为了实现多台客户端同时上传图片使用多线程
new Thre
public static void main(String[] args) throws Exception
{
//接收客户端传来的数据
ServerSocket ss = new ServerSocket(10007);
while(true)
{
//阻塞是方法
Socket s = s
sad(new PicThread(s)).start();
}
//ss.close();
}
}