——- android培训、java培训、期待与您交流! ———-
网络编程
UDP和TCP协议各自优缺点
1)UDP面向无连接,数据报大小有限制64K之内封包,不可靠,容易丢包,但是速度快!因此针对于数据不重要,追求速度快的常用此类协议,如聊天工具/网络视频会议。
2)TCP面向连接,可传输大树据,经过三次握手协议,可靠,但是速度慢,消耗资源。TCP相当于打电话,UDP相当于邮局寄信。下载用的是TCP。
(一)UDP协议
- UDP发送数据步骤四步
1)创建socket对象
2)确定数据,并把数据打包
3)发送数据
4)关闭资源socket
public class UDPSend
{
public static void main(String args[])
{
DatagramSocket ds = new DatagramSocket(8888);
byte[] buf = "hello world!".getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,"192.163.1.34","10000");
ds.send(dp);
ds.close();
}
}
- UDP接受数据步骤
1)创建socket对象,并指定接受端口号
2)定义空的数据报,准备存储接受到的数据,并利用数据报中的方法解析数据的各种信息。
3)接收数据
4)解析数据
5)关闭资源
public class UDPRece
{
public static void main(String args[])
{
DatagramSocket ds = new DatagramSocket(8888);
byte[] buf = new byte[1024];//最大为6k
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String address = dp.getAdrress().getHostAdrress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(address+"..."+data+"..."+port);
ds.close();
}
}
192.168.1.255是个广播地址。可以给所有机器发广播。
示例1: 从键盘接收数据,可以一对一发,也可以群发。
public class UDPSend
{
public static void main(String args[])
{
DatagramSocket ds = new DatagramSocket(8888);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=br.readLine())!=null)
{
if(line.equals("bye"))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.163.1.34"),"10000");
ds.send(dp);
}
ds.close();
}
}
public class UDPRece
{
public static void main(String args[])
{
DatagramSocket ds = new DatagramSocket(8888);
while(true)
{
byte[] buf = new byte[1024];//最大为6k
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String address = dp.getAdrress().getHostAdrress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(address+"..."+data+"..."+port);
}
}
}
示例2:聊天工具,用两个线程来写,同样是从键盘录入数据。
class UDPSend implements Runnable
{
private DatagramSocket ds;
public UDPSend(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=br.readLine())!=null)
{
if(line.equals("bye"))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.163.1.34"),"10000");
ds.send(dp);
}
ds.close();
}
}
class UDPRece implements Runnable
{
private DatagramSocket ds;
public UDPRece(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
while(true)
{
byte[] buf = new byte[1024];//最大为6k
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String address = dp.getAdrress().getHostAdrress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(address+"..."+data+"..."+port);
}
}
}
public class TestDemo
{
public static void main(String args[])
{
DatagramSocket ds1 = new DatagramSocket();
DatagramSocket ds2 = new DatagramSocket(10000);
new Thread(new UDPSend(ds1));
new Thread(new UDPRece(ds2));
}
}
(二)TCP协议
注1:客户端和服务器
注2:需要建立连接才能执行,需要先运行服务器,在运行客户端
客户端建立步骤
1. 创建socket对象,并设置连接地址和端口号
2. 获得输出流
3. 加载数据到输出流中
4. 关闭客户端
class TCPClient
{
public static void main(String args[])
{
Socket sc = new Socket("192.168.1.254",10003);
OutputStream out = ss.getOutputStream();
out.write("hello world".getBytes());
sc.close();
}
}
服务器建立步骤
1. 创建server对象,设置自己的监听端口号
2. 获得客户端socket对象
3. 获得客户端对象的输入流,并读取数据
4. 关闭客户端。
class TCPServer
{
public static void main(String args[])
{
ServerSocket ss = new ServerSocket(10003);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+".......");
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
示例3:客户端发送数据,服务器端接收数据,并反馈给客户端,客户端接收反馈并打印。
class TCPClient
{
public static void main(String args[])
{
Socket s = new Socket("192.168.1.254",10001);
OutputStream out = s.getOutputStream();
out.write("你好,服务器!".getBytes());
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1)
{
System.out.println(new String(buf,0,len));
}
s.close();
}
}
class TCPServer
{
public static void main(String args[])
{
ServerSocket ss = new ServerSocket(10001);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
OutputStream out = s.getOutputStream();
out.write("客户端,谢谢,已收到!!".getBytes());
s.close();
ss.close();
}
}
示例4:客户端通过键盘录入文本数据,服务器将文本转换成大写返回给客户端。
1)用字符缓冲流完成
2)改错。客户端和服务器都在莫名的等待,原因是里面出现了阻塞式方法,这些方法没有读到结束标记,所以一直处于等待状态。
class TCPClient
{
public static void main(String args[])
{
Socket s = new Socket("192.168.1.254",10002);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufbw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
BufferedReader bufbr = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=in.readLine())!=null)
{
if(line.equals("over"))
break;
bufbw.write(line);
bufbw.newLine();
bufbw.flush();
String str = bufr.readLine();
System.out.println("server:"+str);
}
}
}
class TCPServer
{
public static void main(String args[])
{
ServerSocket ss = new ServerSocket(10003);
Socket s = ss.accept();
BufferedReader bufbr = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter bufbw = new BufferedReader(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while((line = bufbr.readLine())!=null)
{
bufbw.write(line.toUpperCase());
bufbw.newLine();
bufbw.flush();
}
s.close();
ss.close();
}
}
示例5:上传文本数据。从客户传送硬盘文件到服务器端硬盘。文本文件。
出现问题:
1)没有结束标记位
2)socket内部定义的结束关闭流标志位的方法。shutdownOutput();
class TCPClient
{
public static void main(String args[])
{
Socket s = new Socket("192.168.1.254",10002);
BufferedReader in = new BufferedReader(new FileReader("c:\\client.txt"));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()),true);
bufbr = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=in.readLine())!=null)
{
pw.println(line);
}
s.shutdownOutput();
String str = bufr.readLine();
System.out.println("server:"+str);
in.close();
s.close();
}
}
class TCPServer
{
public static void main(String args[])
{
ServerSocket ss = new ServerSocket(10003);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
BufferedReader bufbr = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter bw = new BufferedWriter(new FileWriter("d:\\server.txt"),true);
String line = null;
while((line = bufbr.readLine())!=null)
{
bw.write(line);
}
PrintWriter bufbw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
bufbw.write("上传成功!!!!")
s.close();
ss.close();
}
}
示例6:上传图片。(练习)
一个传一个收。
class TCPClient
{
public static void main(String args[])
{
Socket s = new Socket("192.168.1.254",10002);
InputStream in = new FileInputStream("c:\\1.png");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0 ;
while((len=in.read(buf))!=-1)
{
out.write(buf);
}
s.shutdownOutput();
InputStream is = s.getInputStream();
byte[] buf1 = new byte[1024];
int len1 = is.read(buf1);
System.out.println(new String(buf1,0,len1));
in.close();
s.close();
}
}
class TCPServer
{
public static void main(String args[])
{
ServerSocket ss = new ServerSocket(10003);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
InputStream in = s.getInputStream();
OutputStream ou = new FileOutputStream("d:\\2.png");
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1)
ou.write(buf,0,len);
OutputStream out = s.getOutputStream();
out.write("上传成功!!".getBytes());
ou.close();
s.close();
ss.close();
}
}
一个服务器,同时可以处理多个客户端的请求。用多线程处理。
注意:需要开启新的线程,需要保存路径是原有文件不被覆盖,需要传输特定格式和特定大小的文件。
class uploadThread
{
private Socket socket;
public uploadThread(Socket socket)
{
this.socket = socket;
}
public void run()
{
try
{
int count = 1;
String ip = s.getInetAddress().getHostAddress();
InputStream in = s.getInputStream();
File file = new File(ip+"("+count+")"+".png");
while(file.exist())
{
File file = new File(ip+"("+(count++)+")"+".png");
}
OutputStream ou = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1)
ou.write(buf,0,len);
OutputStream out = s.getOutputStream();
out.write("上传成功!!".getBytes());
ou.close();
s.close();
}catch(Exception e)
{
throw new RuntimeException(ip+"上传失败!!")
}
}
}
class TCPServer
{
public static void main(String args[])
{
ServerSocket ss = new ServerSocket(10003);
while(true)
{
Socket s = ss.accept();
new Thread(new uploadThread(s)).start();
}
}
}
class TCPClient
{
public static void main(String args[])
{
if(args.length!=1)
{
System.out.println("请选择一个图片格式的文件上传");
return;
}
File file = args[0];
if(!(file.exist()&&file.isFile()))
{
System.out.println("该文件有问题,要么不存在,要么不是文件格式");
return;
}
if(file.getName().endsWith(".jpg"))
{
System.out.println("该图片格式不正确,请重新选择");
return;
}
if(file.length()>1024*1024*5)
{
System.out.println("文件过大,请重新选择");
return;
}
Socket s = new Socket("192.168.1.254",10002);
InputStream in = new FileInputStream(file);
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0 ;
while((len=in.read(buf))!=-1)
{
out.write(buf);
}
s.shutdownOutput();
InputStream is = s.getInputStream();
byte[] buf1 = new byte[1024];
int len1 = is.read(buf1);
System.out.println(new String(buf1,0,len1));
in.close();
s.close();
}
}
(三) URL
我们所常用的浏览器,实际上就是一个客户端,输入内容为http://IP:端口号?key=alue,就相当于发送请求。
我们把http协议,IP地址,端口号和请求内容封装到一个类中,称为URL。
通过URL,我们可以:
(1)获得协议名称,IP地址,端口号,请求内容等;
(2)可以直接获得客户端和服务器端的连接通道。
public class URLDemo
{
public static void main(String args[]) throws Exception
{
URL url = new URL("http://192.168.1.245:8080/myweb/demo.html?name=hahha&age=39");
System.out.println("getProtocol()"+url.getProtocol());//获得协议
System.out.println("getHost()"+url.getHost());//获得IP地址
System.out.println("getPort()"+url.getPort());//获得端口号
System.out.println("getPath()"+url.getPath());//获得路径
System.out.println("getFile()"+url.getFile());//获得查找内容
System.out.println("getQuery()"+url.getQuery());//获得查找内容
URLConnection con = url.getConnection();//返回数据没有头信息。//这属于应用层。
InputStream in = url.openStream();//直接开流
}
}
需要注意一点:getPort()方法,如果没有输入端口号,则默认为-1;需要如下判断:
int port = url.getPort();
if(port==-1)
port = 80;
以上是网络编程的基本概念和基本思想,多做练习,多理解,多复习。