在写 socket 之前先给大家介绍下 TCP 和 UDP
TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议。其中TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送;而UDP则不为IP提供可靠性、流控或差错恢复功能。
面向连接的TCP
“面向连接”就是在正式通信前必须要与对方建立起连接。比如你给别人打电话,必须等线路接通了、对方拿起话筒才能相互通话。
TCP协议能为应用程序提供可靠的通信连接,使一台计算机发出的字节流无差错地发往网络上的其他计算机,对可靠性要求高的数据通信系统往往使用TCP协议传输数据。
面向非连接的UDP协议
“面向非连接”就是在正式通信前不必与对方先建立连接,不管对方状态就直接发送。与手机短信非常相似:你在发短信的时候,只需要输入对方手机号就OK了。
UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去!
TCP与UDP区别总结:
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
UDP如何实现可靠传输
由于在传输层UDP已经是不可靠的连接,那就要在应用层自己实现一些保障可靠传输的机制
简单来讲,要使用UDP来构建可靠的面向连接的数据传输,就要实现类似于TCP协议的
超时重传(定时器)
有序接受 (添加包序号)
应答确认 (Seq/Ack应答机制)
滑动窗口流量控制等机制 (滑动窗口协议)
等于说要在传输层的上一层(或者直接在应用层)实现TCP协议的可靠数据传输机制,比如使用UDP数据包+序列号,UDP数据包+时间戳等方法。
java 代码实现 tcp
服务端server
public class UploadServer {
public static void main(String[] args) throws IOException {
//1.创建一个ServerSocket
ServerSocket serverSocket = new ServerSocket(8888);
//2.使用ServerSocket监听用户的请求
Socket socket = serverSocket.accept();
//3.接收用户的请求数据并复制到本地
//创建流(输入流和输出流)
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:/women2.mp3"));
//使用流(输入流和输出流)
byte [] buf = new byte[1024];
int len = bis.read(buf);
while(len !=-1){
//写一个字节
bos.write(buf, 0, len);
//输出
//System.out.println((char)n);
//读一个字节
len = bis.read(buf);
}
//手动刷新(输出缓冲区内容写入文件)
//bos.flush();
//关闭流(输入流和输出流)
//bis.close(); //关闭流同时关闭socket
socket.shutdownInput();
bos.close();
//4.给客户端响应(上传成功)
BufferedOutputStream bos2 = new BufferedOutputStream(socket.getOutputStream());
bos2.write("上传成功".getBytes());
bos2.flush();
//5.关闭资源
bis.close();
bos2.close();
socket.close();
serverSocket.close();
}
}
客户端client
public class UploadClient {
public static void main(String[] args) throws UnknownHostException, IOException {
//1.创建一个Socket,连接服务器端
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
//2.复制文件到服务器端
//创建流(输入流和输出流)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("d:/women.mp3")));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
//使用流(输入流和输出流)
byte [] buf = new byte[1024];
int len = bis.read(buf);
while(len !=-1){
//写一个字节
bos.write(buf, 0, len);
//输出
//System.out.println((char)n);
//读一个字节
len = bis.read(buf);
}
//关闭流(输入流和输出流)
bis.close();
//bos.close();
socket.shutdownOutput(); //只想关闭输出流,但是不想同时关闭socket
//3.接收响应信息并输出
BufferedInputStream bis2 = new BufferedInputStream(socket.getInputStream());
len = bis2.read(buf);
System.out.println(len);
System.out.println(new String(buf,0,len));
//4.关闭资源
bos.close();
socket.close();
}
}
java 代码实现 udp
服务端 server 代码
public class AskServer {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1.创建一个DatagramSocket,用来发送或者接收数据
DatagramSocket socket = new DatagramSocket(8888);//8888 接收数据的端口
//2.使用DatagramSocket接收数据
byte [] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
//System.out.println("客户端发来的消息:"+new String(packet.getData(),0,packet.getLength()));
ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData(), 0, packet.getLength());
ObjectInputStream ois = new ObjectInputStream(bais);
//System.out.println(ois.readInt());
//System.out.println(ois.readDouble());
System.out.println(ois.readObject());
//3.使用DatagramSocket发送数据
String reply = "你在线吗?";
byte [] buf2 =reply.getBytes();
DatagramPacket packet2 = new DatagramPacket(buf2, buf2.length, packet.getAddress(), packet.getPort());
socket.send(packet2);
//4.关闭资源
ois.close();
socket.close();
}
}
客户端client 代码
public class AskClient {
public static void main(String[] args) throws IOException {
//1.创建一个DatagramSocket,用来发送或者接收数据
DatagramSocket socket = new DatagramSocket(9999);//接收数据的端口
//2.使用DatagramSocket发送数据
//int num = 10;
//double pi=3.14;
User user = new User("liao","xiong");
//各种数据类型------> byte []
//// start!!!!
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
//oos.writeInt(num);
//oos.writeDouble(pi);
oos.writeObject(user);
byte [] buf = baos.toByteArray();
/////end!
DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getLocalHost(), 8888);
socket.send(packet);
//3.使用DatagramSocket接收数据
byte [] buf2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(buf2, buf2.length);
socket.receive(packet2);
System.out.println("服务器端的反馈:"+new String(buf2,0,packet2.getLength()));
//4.关闭资源
oos.close();
socket.close();
}
}
网友评论