TCP
传输控制协议(TCP)是一种面向连接的、可靠的、基于字节流的传输层协议。
在用java实现TCP连接时,我们需要建立服务器与客户端之间的联系,这个联系我们是通过socket,俗称套接字,来实现,接下来我们看一下代码,首先是
客户端代码
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class TCPCLient {
public static void main(String[] args) {
Socket socket=null;
OutputStream os=null;
try {
//1.我得知道一个地址,端口号
InetAddress serverIp=InetAddress.getByName("127.0.0.1");
int port=9999;
//2.创建一个Socket连接
socket=new Socket(serverIp,port);
//3.发送消息 IO流
os=socket.getOutputStream();
os.write("你好,欢迎学习TCP".getBytes());
} catch (Exceptione) {
e.printStackTrace();
}finally {
if(os!=null){
try {
os.close();
} catch (IOExceptione) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOExceptione) {
e.printStackTrace();
}
}
}
}
}
一定要记得最后关闭资源,先关闭后面创建的。
TCP客户的端步骤如下:
创建socket类,指明主机号,服务器端口号
创建输出流,向服务器发送消息
关闭资源流
服务器代码
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) {
ServerSocket serverSocket=null;
Socket socket=null;
InputStream is=null;
ByteArrayOutputStream baos=null;
{
while(true){
try {
//1.我得有个地址
serverSocket=new ServerSocket(9999);
//2.等待客户端连接过来
socket=serverSocket.accept();
//3.读取客户端的消息
is=socket.getInputStream();
/*
byte[] buffer = new byte[1024];
int len;
while((len=is.read(buffer))!=-1){
String msg = new String(buffer, 0, len);
System.out.println(msg);
}
*/
//管道流
baos=new ByteArrayOutputStream();
byte[] buffer=newbyte[1024];
int len;
while((len=is.read(buffer))!=-1){
baos.write(buffer,0,len);
}
System.out.println(baos.toString());
} catch (IOExceptione) {
e.printStackTrace();
}finally {
//关闭资源
if(baos!=null){
try {
baos.close();
} catch (IOExceptione) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOExceptione) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOExceptione) {
e.printStackTrace();
}
}
if(serverSocket!=null){
try {
serverSocket.close();
} catch (IOExceptione) {
e.printStackTrace();
}
}
}
}
}
}
}
可以看到我们中间用到了管道流来接受资源,也就是ByteArrayOutputStream,其实通过名字我们也可以知道ByteArrayOutputStream是对byte类型数据进行写入的类,并且相当于一个中间缓冲层,将类写入到文件等其他outputStream。它是对字节进行操作,属于内存操作流。
TCP服务器的步骤如下:
创建ServerSocket,设置端口号
ServerSocket.accept进行监听,等待客户端到来
创建输入流进行接受消息
将收到的消息输出
关闭资源流
tips:需要注意的是,服务器的端口号是我们需要自己设置的,因为在客户端连接的时候,需要连接与客户端相同的端口号,两者必须相同,不然无法通信。
我们在此处设置的ip地址127.0.0.1,是我们本机地址
必须先开启服务器,再开启客户端
TCP文件传输
只要掌握的TCP传输的原理步骤,其他的操作都大同小异,最基本的步骤都是一样的只是在中间加入了一些其他操作,像文件传输,我们只需在客户端加入文件输入流,把文件先读取再输出给服务器,服务器则只需加入文件输出流保存文件即可。
客户端代码:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class FileTcpClient {
public static void main(String[] args) {
try {
InetAddress id=InetAddress.getByName("127.0.0.1");
Socket socket=new Socket(id,9999);
OutputStream os=socket.getOutputStream();
FileInputStream fis=new FileInputStream("TCP.jpg");
byte[] buffer=new byte[1024];
int len;
while((len=fis.read(buffer))!=-1){
os.write(buffer,0,len);
}
//通知服务器我已经结束 已经传输完了
socket.shutdownOutput();
InputStream is=socket.getInputStream();
ByteArrayOutputStream baos=newByteArrayOutputStream();
byte[] buffer2=new byte[1024];
int len2;
while((len2=is.read(buffer2))!=-1){
baos.write(buffer2,0,len2);
}
System.out.println(baos.toString());
baos.close();
is.close();
fis.close();
os.close();
socket.close();
} catch (Exceptione) {
e.printStackTrace();
}
}
}
服务器代码:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class FileTcpServer {
public static void main(String[] args) {
try {
ServerSocket serverSocket=new ServerSocket(9999);
Socket socket=serverSocket.accept();
InputStream is=socket.getInputStream();
FileOutputStream fos=new FileOutputStream(newFile("MyPhoto.jpg"));
byte[] buffer=new byte[1024];
intlen;
while((len=is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
OutputStream os=socket.getOutputStream();
os.write("我已经接收完毕,你可以关闭了".getBytes());
//关闭资源
os.close();
fos.close();
is.close();
socket.close();
serverSocket.close();
} catch (Exceptione) {
e.printStackTrace();
}
}
}
注意到,我们在客户端发送完毕的时候用到了shutdownOutput,调用Socket.shutdownOutput()方法后,客户端输出的数据都将被发送,并加上 TCP 的正常连接终止序列(-1,也就是服务端终止循环的判断条件),这样服务端读取数据时就不会被阻塞了。