------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
网络模型
OSI(Open System Interconnection开放系统互连)参考模型
TCP/IP参考模型
网络通讯要素
IP地址
端口号
传输协议
网络通讯要素:
IP地址:InetAddress
网络中设备的标识
不易记忆,可用主机名
本地回环地址:127.0.0.1 主机名:localhost
端口号
用于标识进程的逻辑地址,不同进程的标识
有效端口:0~65535,其中0~1024系统使用或保留端口。
传输协议
通讯的规则
常见协议:TCP,UDP
TCP和UDP:
1,UDP:
将数据及源和目的封装成数据包中,不需要建立连接
每个数据报的大小在限制在64k内
因无连接,是不可靠协议
不需要建立连接,速度快
2,TCP:
建立连接,形成传输数据的通道。
在连接中进行大数据量传输
通过三次握手完成连接,是可靠协议
必须建立连接,效率会稍低
------------------------------------------------
Socket
Socket就是为网络服务提供的一种机制。
通信的两端都有Socket。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO传输。
------------------------------------------------------------------
UDP传输
DatagramSocket与DatagramPacket
建立发送端,接收端。
建立数据包。
调用Socket的发送接收方法。
关闭Socket。
发送端与接收端是两个独立的运行程序
发送端
在发送端,要在数据包对象中明确目的地IP及端口。
DatagramSocket ds = new DatagramSocket();
byte[] by = “hello,udp”.getBytes();
DatagramPacket dp = new DatagramPacket(by,0,by.length,
InetAddress.getByName(“127.0.0.1”),10000);
ds.send(dp);
ds.close();
接收端
在接收端,要指定监听的端口。
DatagramSocket ds = new DatagramSocket(10000);
byte[] by = new byte[1024];
DatagramPacket dp = new DatagramPacket(by,by.length);
ds.receive(dp);
String str = new String(dp.getData(),0,dp.getLength());
System.out.println(str+"--"+dp.getAddress());
ds.close();
整体演示:
package cn.itcast.net.p3.chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class UDPChatTest {
/**
* @param args
* @throws SocketException
*/
public static void main(String[] args) throws SocketException {
//1,创建接收端和发送端。
DatagramSocket send = new DatagramSocket(1919);
DatagramSocket rece = new DatagramSocket(10001);
new Thread(new Send(send)).start();
new Thread(new Rece(rece)).start();
}
}
//定义发送任务。
class Send implements Runnable{
private DatagramSocket ds ;
public Send(DatagramSocket ds) {
super();
this.ds = ds;
}
public void run(){
try{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=bufr.readLine())!=null){
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10001);
ds.send(dp);
if("over".equals(line))
break;
}
ds.close();
}
catch(IOException e){
}
}
}
//定义接收任务。
class Rece implements Runnable{
private DatagramSocket ds ;
public Rece(DatagramSocket ds) {
super();
this.ds = ds;
}
public void run(){
try {
byte[] buf = new byte[1024];
while(true){
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String text = new String(dp.getData(),0,dp.getLength());
System.out.println(ip+":"+text);
if("over".equals(text)){
System.out.println(ip+".....离开聊天室");
}
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
TCP传输
Socket和ServerSocket
建立客户端和服务器端
建立连接后,通过Socket中的IO流进行数据的传输
关闭socket
同样,客户端与服务器端是两个独立的应用程序。
客户端
通过Socket建立对象并指定要连接的服务端主机以及端口。
Socket s = new Socket(“192.168.1.1”,9999);
OutputStream out = s.getOutputStream();
out.write(“hello”.getBytes());
s.close();
建立客户端:
package cn.itcast.net.p1.uploadtext;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class UploadTextClient {
/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
/*
* 需求:读取一个本地文件,将数据发送到服务端,服务器端对数据进行存储。
* 存储完毕后,给客户端一个提示。
* 文本文件上传。
*/
//1,创建客户端socket服务。
Socket s = new Socket("192.168.1.100",10005);
//2,读取本地文件,
BufferedReader bufr = new BufferedReader(new FileReader("tempfile\\client.txt"));
//3,确定目的:网络。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line = null;
while((line=bufr.readLine())!=null){
out.println(line);
}
//给服务端发送一个结束标记,使用Socket对象的shutdownOutput()方法。
s.shutdownOutput();
//给服务端发送一个自定义结束标记。后期可以使用事件毫秒值字符串。
// out.println("over");
//4,读取服务端的回馈信息。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String text = bufIn.readLine();
System.out.println("server:"+text);
bufr.close();
s.close();
}
}
服务端
建立服务端需要监听一个端口
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept ();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int num = in.read(buf);
String str = new String(buf,0,num);
System.out.println(s.getInetAddress().toString()+”:”+str);
s.close();
ss.close();
建立服务端
package cn.itcast.net.p1.uploadtext;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class UploadTextServer {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 服务端:对客户端发送的数据进行接收并存储到一个文件中。
* 并对客户端进行"上传成功"字样的返回。
*/
//1,创建服务器端socket服务。
ServerSocket ss = new ServerSocket(10005);
//2,获取客户端对象。
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress()+"......connected");
//3,读取客户端发来的数据。源。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
//4,将数据写入到一个文件中。
PrintWriter pw = new PrintWriter(new FileWriter("tempfile\\server.txt"),true);
String line = null;
while((line=bufIn.readLine())!=null){
// if("over".equals(line)){
// break;
// }
pw.println(line);
}
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("上传成功");
pw.close();
s.close();
ss.close();
}
}
Tcp传输最容易出现的问题
客户端连接上服务端,两端都在等待,没有任何数据传输。
通过例程分析:
因为read方法或者readLine方法是阻塞式。
解决办法:
自定义结束标记
使用shutdownInput,shutdownOutput方法