1.区别:
TCP 面向连接;UDP 不建立可靠连接
TCP 信息包头 20 个字节;UDP 8 个字节
TCP 只能一对一的传输;UDP 支持一对一、一对多、多对一、多对多的传输
TCP 需要维护连接状态;UDP 无
TCP 拥有流量控制及拥塞控制的机制;UDP 不关注网络状况
TCP 通过流模式传输数据;UDP 通过数据报模式传输数据
TCP 保证数据正确性、不丢包、不重复、有序性;UDP 只最大交付,不保证可靠性
TCP 适合网络负担不大、可靠性要求高的场景;UDP 适合网络负担重响应高、客户端较多、可靠性要求不高的场景
2.1 使用tcp创建一个客户端
package com.socket;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class LoginClient {
public static void main(String[] args) {
OutputStream os=null;
Socket socket=null;
try {
//表示建立一个tcp的客户端 1参表示发送地址,2参表示发送端口
socket=new Socket("localhost", 8800);
//发送信息要借助什么? 给服务器发送的信息。定义发送信息
String info="服务器你好!";
//通过socket对象获取到字节输出流
os=socket.getOutputStream();
//将信息发送给服务器。wirte发送的是字节。所以要string转为byte
os.write(info.getBytes());
//关闭发送端
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.2 使用tcp创建一个服务端
package com.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class LoginServer {
public static void main(String[] args) {
BufferedReader br=null;
InputStream is=null;
Socket socket=null;
ServerSocket ss=null;
try {
//表示创建一个tcp服务端 端口号是8800 用于接收用户的信息
ss=new ServerSocket(8800);
//使用tcp服务端 接收方法 来接收请求 返回的就是一个socket
socket=ss.accept();
//socket获得读取的字节内容
is=socket.getInputStream();
//创建字符流对象 需要InputStreamReader(这里写入is对象)
br=new BufferedReader(new InputStreamReader(is));
//定义一个字符串 用来接收数据
String info;
while((info=br.readLine())!=null) {
System.out.println("客户端发送的信息是"+info);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
socket.close();
br.close();
ss.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
3. 1 使用tcp和线程传输对象 (创建服务端)
package com.threadsocket;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class LoginServer {
public static void main(String[] args) {
try {
//创建tcp服务端
ServerSocket ss=new ServerSocket(8802);
//一直保持服务端处于获取状态
while(true) {
//tcp服务端获取数据方法
Socket socket=ss.accept();
//线程构造函数,传入一个 socket获取
LoginThread lt=new LoginThread(socket);
new Thread(lt).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.2 使用tcp和线程传输对象(创建客户端)
package com.threadsocket;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class LoginClient1 {
//使用多线程 模拟多个用户登录
//多个用户就是多个客户端
//服务器只有一个 必须让服务器一直处于开启状态 或者说监听状态
//写一个线程类用户处理客户端的请求
public static void main(String[] args) {
try {
Socket socket=new Socket("localhost",8802);
Stu stu=new Stu("赵四", "6666");
OutputStream os=socket.getOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(os);
oos.writeObject(stu);
oos.flush();
oos.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.3 创建线程(用于服务端调用)
package com.threadsocket;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.Socket;
public class LoginThread implements Runnable{
//为了区分不同的socket
private Socket socket;
//创建构造函数,传入socket参数
public LoginThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//用传入的socket获取字节流
InputStream is= socket.getInputStream();
ObjectInputStream ois=new ObjectInputStream(is);
Stu stu=(Stu) ois.readObject();
System.out.println("服务器获取到客户端发送的信息"+stu);
ois.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
UDP发送数据Dome
1.使用udp创建客户端
package com.udp.DatagramSocket;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class LoginClient {
//tcp是面向连接的
//udp是非面向连接的
public static void main(String[] args) {
try {
//建立udp客户端
DatagramSocket ds=new DatagramSocket();
//发送消息的内容 数据大小 数据地址 端口号
String info="卢你好";
byte[] b=info.getBytes();//字符串转为字符型数组
//发送到的地址名
InetAddress ia=InetAddress.getByName("10.8.165.31");
//把数据打包
DatagramPacket dp=new DatagramPacket(b, b.length, ia, 8802);
//把数据发送
ds.send(dp);
//定义接收数据的大小
byte[] newb=new byte[1024];
DatagramPacket newdp=new DatagramPacket(newb, newb.length);
//接收数据,并没有返回值
ds.receive(newdp);
//因为没有返回值,需要用new String输出包中的数据,可以在此设置字符集
System.out.println("服务端发送的是"+newString(newdp.getData(),0,newdp.getData().length));
System.out.println("服务端发送的数据是"+new String(newdp.getData(), "utf-8"));
ds.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.2使用udp创建服务端
package com.udp.DatagramSocket;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketException;
public class LoginServer {
public static void main(String[] args) {
try {
//udp的传输方式 建立udp服务端
DatagramSocket ds=new DatagramSocket(8899);
//接受数据之前。需要建立数据的大小。
byte[] datas=new byte[1024];
//因为数据是非面向连接的。所以数据是以包的形式打包接收的。数据的包名。和数据的大小
DatagramPacket dp=new DatagramPacket(datas, datas.length);
//接收的方法名。没有返回值
ds.receive(dp);
//因为没有返回值。所以使用String方法。1.得到该数据 2.从第几个数据开始。长度为字节 3.数据的长度。
System.out.println("接收到的数据是"+new String(dp.getData(), 0, dp.getData().length));
//服务端收到数据后 向发送端回复数据
byte[] b="你好 客户端".getBytes();
//getSocketAddress 用来获取客户端发来包的地址
SocketAddress address=dp.getSocketAddress();
DatagramPacket dgp=new DatagramPacket(b, b.length, address);
//发送方法
ds.send(dgp);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}