一、概述
网络编程的本质是通过io流使得两个设备之间传递数据。网络编程一般采用请求/响应式,第一次发送请求的为客户端,而服务端对客户端的请求进行反馈。
网络通讯的要素有:
ip地址 就是网络中设备的标识。
端口 用于标识进程的逻辑地址,不同进程的标识。有效端口:0~65535,其中0~1024系统使用或保留端口。网站大多用8080端口。
传输协议 通讯的规则常见协议:TCP,UDP。
如果把网络通讯视为你想去拜访某人,ip地址就像你需要先知道他的家庭地址,端口就像在他家哪儿开始聊天,传输协议就是你们用哪国语言聊天。
UDP是一个不可靠协议,它将数据源和目的地封装到数据包中,不需要建立连接,包的大小限制在64K以内,因为不需要创建连接,他传输速度很快,但是容易发生丢包。
TCP是个可靠协议,通过三次握手完成连接,速度比UDP慢,但是不易丢失数据,适合大数据传递。
Socket是为网络服务提供的一种机制。通信的两端都有Socket,网络通信其实就是Socket间的通信。数据在两个Socket间通过IO传输。
二、UDP和TCP
Udp通过DatagramSocket和DatagramPacket类来完成传输数据。
DatagramSocket类表示用来发送和接收数据报包的套接字
DatagramPacket类则是对数据包进行包装和拆包
下面是一个通过udp传递消息的小例子
import java.net.*;
import java.io.*;
class TalkDemo{
public static void main (String []args) throws Exception{
DatagramSocket sendSocket = new DatagramSocket(); //创建一个udp服务
DatagramSocket receSocket = new DatagramSocket(8888); //创建一个udp服务,端口为8888
new Thread(new Send(sendSocket)).start(); //创建一个发送端的线程
new Thread(new Rece(receSocket)).start(); //创建一个接受端的线程
}
}
class Send implements Runnable{
private DatagramSocket ds ;
public Send(DatagramSocket ds){
this.ds = ds;
}
public void run(){
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //转换流来读取屏幕输出
String line = null ;
while( (line = br.readLine())!=null ){
byte []buf = line.getBytes();
DatagramPacket dp = new DatagramPacket ( buf,buf.length ,InetAddress.getByName("192.168.1.101"),8888) ;//封包处理
ds.send(dp); //发送
}
}
catch (Exception e){
throw new RuntimeException("发送端失败");
}
}
}
class Rece implements Runnable{
private DatagramSocket ds2 ;
public Rece(DatagramSocket ds2){
this.ds2 = ds2;
}
public void run(){
try{
while(true){
byte []buf2 = new byte[1024];
DatagramPacket dp2 = new DatagramPacket ( buf2,buf2.length ) ;
ds2.receive(dp2); //接收包
PrintStream os = new PrintStream( System.out,false); //新建一个打印流
os.write(buf2,0,dp2.getLength());
os.println(); //换行
os.flush(); //刷新打印流
}
}
catch (Exception e){
throw new RuntimeException("接收端失败");
}
}
}
TCP分服务端和客户端,分别利用ServerSocket和Socket来创建。
TCP的客户端:通过查阅Socket对象,发现在该对象建立时,就可以连接指定主机、因为tcp是面向连接的,所以在建立socket服务时,就要有服务端存在,并连接成功,形成通路后,在该通道进行数据的传输。
TCP的服务端:1.服务端的socket服务,ServerSocket();并监听一个端口,
2.通过ServerSocket的accept方法获取连接过来的客户端对象,这个方法是阻塞式的
3.使用多线程为连接过来的客户端创建一个服务线程。
4.关闭和客户端之间的连接。
5.关闭服务端(一般不使用);
import java.io.*;
import java.net.*;
class PicServer{
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(9999);
while(true){
Socket s = ss.accept();
new Thread(new SavePic(s)).start();
}
}
}
class SavePic implements Runnable{
private Socket s;
private FileOutputStream fos;
SavePic(Socket s){
this.s = s;
}
public void run (){
try{
InputStream in = s.getInputStream();
fos = new FileOutputStream("d:\\bbb.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1){
fos.write(buf,0,len);
}
BufferedWriter out = new BufferedWriter ( new OutputStreamWriter(s.getOutputStream()));
out.write("上传成功");
out.newLine();
out.flush();
System.out.print(s.getInetAddress().getHostAddress());
}
catch(Exception e){
}
finally{
if(fos!=null){
try{
fos.close();
}
catch(Exception e){}
}
;
if(s!=null){
try{
s.close();
}
catch(Exception e){}
}
}
}
}
//客户端
import java.io.*;
import java.net.*;
class PicClient{
public static void main (String []args) throws Exception{
Socket s = new Socket("192.168.1.101",9999);
InputStream in = new FileInputStream("d:\\aaa.bmp");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1){
out.write(buf,0,len);
}
s.shutdownOutput(); //没有这语句服务器将不停接收
String line = null;
System.out.println(1);
while( (line=br.readLine())!=null ){
System.out.println(line);
}
s.close();
}
}