TCP,UDP编程:
http://域名:端口号/网站名称/hello.html
http://www.baidu.com:80(80端口是在地址栏输入的时候省略不写)
UDP编程:
UDP是一种简单的不可靠的无连接的网络数据传输协议,并不保证数据报包会顺利的到达指定的主机,也不保证数据报包会按照发送的顺序到达指定的主机。UDP传输数据类似于邮局寄信取信。将信息封装成数据报包,在包上指定目的IP地址和端口号,来投递到目的主机上。接收时也可通过数据报包来看发送发的IP地址和端口号 。
(1)创建数据报套接字
1)服务器端通常用
public DatagramSocket(int port) throws SocketException
在创建时指定端口号
客户端在发送数据时,将数据报的端口号与此对应.
2)客户端通常用
public DatagramSocket() throws Socket
此方法会为会为该数据报套接字自动分配一个可用端口号.
注意:每台计算机的每个端口号最多只能分配给一个数据报套接字实例对象,因此如果客户端和服务器端如果位于同一台计算机上,则它们不能采用相同的端口号.而采用无参构造的方法刚好可以避开这个问题.服务器端在接受到客户端发送的数据报包,可通过该数据包获取到客户端的端口号,及地址.
(2)发送数据报包
String message=”要发送的信息”;
//转化为字节数组发送
byte[] bytes=message.getBytes();
//创建数据报包
//客户端发送数据报包的创建
InetAddress serverAddress=InetAddress.getByName(“127.0.0.1”);//通过服务器的IP地址字符串形式,得到IP地址
DatagramPacket outPacket=new DatagramPacket(bytes,bytes.length,serverAddress,serverPort);
//服务器端发送数据报包的创建
InetAddress clientAddress=inPacket.getAddress();
int clientPort=inPacket.getPort();
DatagramPacket outPacket=new DatagramPacket(bytes,bytes.length,clientAddress,clientPort);
//发送数据报包
//利用数据报套接字对象调用send方法
dSocket.send(outPacket);
(3)接收数据报包
//public DatagramPacket(byte[] buf,int length)
//参数buf用于指定接受数据存放的数据空间,Length指定最大可以接受的数据正文的字节数,如果参数Length小于接受数据正文部分的实际字节数,则在接受数据时只接受length字节前的数据.
//所以需要先指定一个容器,用于存放数据
byte[] inBuffer=new byte[100];
inPacket=new DatagramPacket(inBuffer,inBuffer.length);
dSocket.receive(inPacket);//接收数据报包
//显示接收到的数据报包的信息
//相当于将字节数组转换为字符串
String s=new String(inPacket.getData,0,inPacket.getLength());
//inPacket.getData获取数据正文 inPacket.getLength()获取数据正文长度
UDP编程的代码:
UDP发送端:
(相当于客户端)
/* UDP协议(发送端和接收端),不需要建立连接通道 * * 发送端 * 步骤: * 1)创建UDP协议发送端的Socket对象 * 2)创建数据报包:通过这个数据包将数据发送到接收端 * 3)调用UDP协议发送端发送的方法 * 4)关闭资源 * @author Apple */public class SendDemo {public static void main(String[] args) throws Exception {//使用UDP协议创建Socket对象不是Socket类对象,(客户端的套接字)//DatagramSocket:用来发送和接收数据报包的套接字。//public DatagramSocket() throws SocketExceptionDatagramSocket ds = new DatagramSocket() ;//创建了UDP协议的Socket对象//发送一句话String str = “hello,udp,i’m coming” ;//2)创建数据报包对象// public DatagramPacket(byte[] buf, int length ,InetAddress address,int port)//将字符串数据转换成字节数组byte[] bys = str.getBytes() ;//当前字节数组的实际长度int len = bys.length ;//创建InetAddress对象,Ip地址对象InetAddress address = InetAddress.getByName(“192.168.10.101”) ;//指定端口号:0-65535是有效端口号int port = 10086 ;DatagramPacket dp = new DatagramPacket(bys, len, address, port) ;//3)调用UDP协议DataScoket类里面发送的方法//public void send(DatagramPacket p) throws IOException从此套接字发送数据报包ds.send(dp) ;//4)关闭资源ds.close() ;}}
UDP接收端:
(相当于服务器端)
/* UDP协议的接收端 * * 1)创建接收端的Socket对象 * 2)创建一个数据报包接收发送端发送来的数据报包(接收容器) * 3)接收数据,调用DataScoket类中的接收的方法来接收数据包 * 4)解析数据报包里面的实际数据,显示在控制台上 * 5)关闭资源 * * * 多次运行接收端,会出现一处:BindException:绑定异常: * 接收端运行一次就可以了,端口号已经被占用了,不能再继续使用这个端口号 * @author Apple */public class ReceiveDemo {public static void main(String[] args) throws IOException {//public DatagramSocket(int port)//1)创建UDP协议接收端的scoket对象DatagramSocket ds = new DatagramSocket(10086) ;//2)创建数据报包:DatagramPacket,来接收发送端发送来的数据//public DatagramPacket(byte[] buf,int length)构造 DatagramPacket,用来接收长度为 length 的数据包。//定义字节数组:缓存区byte[] bys = new byte[1024] ;DatagramPacket dp = new DatagramPacket(bys, bys.length) ;//3)调用DataScoket里面接收的方法// public void receive(DatagramPacket p) throws IOException从此套接字接收数据报包ds.receive(dp) ;// 阻塞式方法(等待发送端发送数据,只要没有数据,就一直等待,有数据的话将数据显示控制)//4)4)解析数据报包里面的实际数据,显示在控制台上//获取到ip字符串表现形式//public InetAddress getAddress():首先通过数据报包得到一个Ip地址对象:InetAddressInetAddress address = dp.getAddress() ;//可以通过getHostAddress()得到ip地址的文本形式String ip = address.getHostAddress() ;//解析发送端发送来的实际数据// byte[] getData() 返回数据缓冲区。// int getLength() 返回将要发送或接收到的数据的长度。byte[] dataBys = dp.getData() ;//获取数据缓存区中的实际长度int len = dp.getLength() ;//将字符串显示出来String str = new String(dataBys,0,len) ;//输出到控制台System.out.println(ip+”:给你发送了:”+str);}}
SendTest.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* 发送端的数据来源不是简单的一条语句而是不停的键盘录入
*
* 键盘录入的方式:
* 1)Scanner类
* 2)BufferedReader类(字符缓冲流)特有功能:readLine():一次读取一行 (System.in)
*
* 快传,QQ
* @author Apple
*/
public class SendTest {
public static void main(String[] args) throws IOException {
//创建发送端的Socket对象
DatagramSocket ds = new DatagramSocket() ;
//以IO流的读取键盘录入的数据发送到接收端
//字符缓冲流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
//一次读取一行
String line = null ;
while((line=br.readLine())!=null){
//发送端不停的发送数据应该有一个结束条件
//自定义结束条件
if("886".equals(line)){
break ;
}
//创建数据报包
//DatagramPacket(byte[] bys,int length,InetAddrss address,int port)
byte[] bys = line.getBytes() ;
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.10.101"), 12345);
//发送数据
ds.send(dp) ;
}
//释放资源
ds.close() ;
}
}
ReceiveTest.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
* 接收端不停的接收键盘录入的数据显示到控制台上
* @author Apple
*/
public class ReceiveTest {
public static void main(String[] args) throws IOException {
//创建接收端的socket对象
DatagramSocket ds = new DatagramSocket(12345) ;
while(true){
byte[] bys = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(bys, bys.length) ;
//接收数据
ds.receive(dp) ;
//获取ip字符串的表现形式
String ip = dp.getAddress().getHostAddress() ;
//解析数据接收容器,获取里面实际的内容
byte[] buff = dp.getData();
int len = dp.getLength() ;//获取实际数据缓冲区实际长度
String s = new String(buff, 0, len) ;
//显示到控制台
System.out.println("from" + ip +"data is :"+s);
// //释放资源,为了模仿一直有发送端发送来的数据,所以无需关闭接收端Socket
// ds.close() ;
}
}
}
需求:接收端和发送端是在两个窗口中显示的,如何让这两个接收端和发送端处于一个窗口下(main中)
(使用多线程第二种方式:Runable接口的方式实现 发送端和接收端处于一个主线程中)
package myUdp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class SendThread implements Runnable{
DatagramSocket ds;
public SendThread(DatagramSocket ds) {
super();
this.ds = ds;
}
@Override
public void run() {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String line=null;
try {
while((line=br.readLine())!=null){
//结束条件
if("over".equals(line)){
break ;
}
byte[] bytes=line.getBytes();
DatagramPacket outPacket=new DatagramPacket(bytes,bytes.length,InetAddress.getByName("192.168.1.102"),8088);
ds.send(outPacket);
}
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(ds!=null) {
ds.close();
}
}
}
}
package myUdp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveThread implements Runnable{
private DatagramSocket ds;
private byte[] inBuffer=new byte[100];
public ReceiveThread(DatagramSocket ds) {
super();
this.ds = ds;
}
@Override
public void run() {
try {
while(true) {
DatagramPacket dp=new DatagramPacket(inBuffer,inBuffer.length);
ds.receive(dp);
byte[] temp=dp.getData();
int len=dp.getLength();
String s=new String(temp,0,len);
System.out.println(dp.getAddress().toString()+":"+s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package myUdp;
import java.net.DatagramSocket;
import java.net.SocketException;
public class ChatRoom {
public static void main(String[] args) throws SocketException {
ReceiveThread rs=new ReceiveThread(new DatagramSocket(8088));
SendThread st=new SendThread(new DatagramSocket());
Thread receive=new Thread(rs);
Thread send=new Thread(st);
receive.start();
send.start();
}
}
TCP编程
TCP是一种基于连接的协议。服务器端和客户端必须先通过IP地址和端口号建立起连接,然后通过socket获取通道的流进行两端的数据通信。
package org.westos_06;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* TCP协议的服务器端
*
* 1)创建服务器端的socket对象,指定端口
* 2)服务器端需要监听客户端的连接
* 3)获取通道内的输入流
* 4)将数据获取到并显示到控制台
* 5)关闭服务器端的socket资源
* @author Apple
*/
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1)ServerSocket此类实现服务器套接字。服务器套接字等待请求通过网络传入
//public ServerSocket(int port) 构造方法:创建绑定到特定端口的服务器套接字
ServerSocket ss = new ServerSocket(10010) ;
System.out.println("等待客户端连接...");
//2)监听客户端的连接:请求等待介入
//public Socket accept()
// throws IOException侦听并接受到此套接字的连接
//该方法特点:服务器在连接到客户端之前,此方法一直处于阻塞
Socket s = ss.accept() ;//一旦客户端那边也是端口,阻塞式方法就会结束
System.out.println("客户端已经连接...");
//3)获取通道内的输入流对象
//public InputStream getInputStream()
InputStream in = s.getInputStream() ;
//4)将客户端发送的数据显示到控制台上
//定义一个缓冲数组
byte[] bys = new byte[1024] ;
int len = in.read(bys) ;//获取到实际的字节数 (阻塞式)
String str = new String(bys, 0, len) ;
//获取IP地址的文本形式
// public InetAddress getInetAddress()返回套接字连接的地址。
InetAddress address = s.getInetAddress() ;
//在通过ip地址对象getHostName();
String ip = address.getHostAddress() ;
//输出显示到控制台
System.out.println(ip+"传递的数据是:"+str);
//关闭服务器端socket
s.close() ;
}
}
package org.westos_06;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/**
* 使用Socket编程里面的TCP协议
* 客户端和服务器端的交互
* 客户端步骤:
* 1)创建客户端的socket对象 (客户端套接字流的形式)
* 2)获取通道的内流(输出流)
* 3)使用输出流对象写数据
* 4)关闭客户端的Socket对象
*
* 对于TCP协议来说:客户端和服务器端是需要建立连接通道的,如果没有启动服务器端,先启动客户端:
* 报异常:java.net.ConnectException
* Connection refused: connect :连接被拒绝!
* @author Apple
*/
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1)1)创建客户端的socket对象:此类实现客户端套接字
//构造方法:Socket类
//public Socket(InetAddress address, int port)
//throws IOException创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
// Socket s = new Socket(InetAddress.getByName(“192.168.10.101”), 10010) ;
//public Socket(String host, int port)
//host:可以是主机名称也可是ip地址的字符串表现形式
Socket s = new Socket(“192.168.10.101”, 10010) ;
//2) 获取通道的内流(输出流)
//public OutputStream getOutputStream()
//throws IOException返回此套接字的输出流。
OutputStream out = s.getOutputStream() ;
//3)客户端通道内的流给服务器写数据
out.write("hello,TCP,我来了...".getBytes()) ;
//4)关闭客户端socket
s.close() ;
}
}
复制上传图片文件
package myTcp;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
/**
* 客户端的图片文件,服务器端输出一个图片文件并且给出反馈
*
* 分析:图片文件使用字节流读取
* @author 花花
*
*/
public class ClientImage {
public static void main(String[] args) throws IOException {
Socket s=new Socket("10.101.216.94",8689);
BufferedOutputStream bos=new BufferedOutputStream(s.getOutputStream());
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("D:\\images\\巧克力色微凉青春.jpg"));
byte[] bytes=new byte[1024];
int len;
while((len=bis.read(bytes))!=-1) {
bos.write(bytes,0,len);
}
s.shutdownOutput();
InputStream is=s.getInputStream();
int len2=is.read(bytes);
System.out.println(new String(bytes,0,len2));
//关闭资源
bis.close();
s.close();
}
}
package myTcp;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerImage {
public static void main(String[] args) throws IOException {
ServerSocket ss=new ServerSocket(8689);
Socket s=ss.accept();
BufferedInputStream bis=new BufferedInputStream(s.getInputStream());
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("如果我们.jpg"));
byte[] bytes=new byte[1024];
int len;
while((len=bis.read(bytes))!=-1) {
bos.write(bytes,0,len);
bos.flush();
}
OutputStream os=s.getOutputStream();
os.write("服务器端复制完毕".getBytes());
bos.close();
s.close();
}
}