tcp的特点:
- tcp协议通讯是面向连接的,tcp的客户端一旦建立,马上要与服务端建立连接。
- tcp协议在连接中传输大数据量,tcp是基于IO流进行数据传输。
- 通过三次握手机制连接,可靠协议(保证数据传输的完整性)
- 因为tcp是面向连接的,所以效率稍低.
- tcp协议是分客户端与服务端。
比如:QQ文件传输、 飞Q文件传输、 打电话...
tcp协议下的Socket :
Socket(客户端类)
ServerSocket(服务端类)
一个网络程序如果能够接收消息与发送消息,那么至少会占用两个端口。
1.第一个小例子
客户端
public class Demo1Client {
public static void main(String[] args) throws Exception {
//第一步: 建立tcp的客户端服务
Socket socket = new Socket(InetAddress.getLocalHost(), 9090);
//第二步: 准备 数据 , 获取对应的流通道。
String data = "这个是我第一个tcp的例子";
OutputStream out = socket.getOutputStream();
//第三步: 可以吧数据写出
out.write(data.getBytes());
//客户端要接收服务端回送的数据
//获取socket的输入流
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int length =inputStream.read(buf);
System.out.println("客户端接收到的内容是:"+ new String(buf,0,length));
//第四步:关闭资源
socket.close();
}
}
服务器端
public class Demo1Server {
public static void main(String[] args) throws Exception {
//第一步: 建立tcp的服务端。
ServerSocket serverSocket = new ServerSocket(9090);
//第二步:接受客户端的连接
Socket socket = serverSocket.accept(); // accept() 是一个阻塞型的方法,没有客户端与其连接的时候,一致等待下去
//第三步: 获取socket对应的流通道
InputStream inputStream = socket.getInputStream();
//第四步: 通过输入流通道读取数据
byte[] buf = new byte[1024];
int length = inputStream.read(buf);
System.out.println("服务端接收到的数据:"+ new String(buf,0,length));
//服务端给客户端回送数据客户端
//获取socket的输出流
OutputStream out = socket.getOutputStream();
out.write("客户端你辛苦啦!!".getBytes());
//第五步: 关闭资源
serverSocket.close();
}
}
从第一个例子可见,客户端使用了socket的流通道去发送数据,而在服务器中发送返回信息的流通道正是从客户端的socket中得来,那么也就衍生了一个问题,为什么服务器中的流通道不是通过ServerSocket.getInputStream/getOutputStream中得来的呢?
其实服务器是可以跟多台客户端连接的,收到的各个客户端的数据不可能通过一个ServerSocket的流通道去响应吧,谁知道该回应给哪个客户端啊, 所以直接使用从每个客户端中得来的socket进行一对一响应
2.模拟服务器发送图片的场景
获取图片的客户端
public class ImageClient {
public static void main(String[] args) throws Exception {
//第一步: 建立tcp客户端服务。
Socket socket= new Socket(InetAddress.getByName("192.168.1.68"),9090);
//获取socket的输入流对象
InputStream inputStream = socket.getInputStream();
//建立一个文件的输出流对象
FileOutputStream fileOutputStream = new FileOutputStream("f:\\美女.jpg");
//边读边写
byte[] buf = new byte[1024];
int length = 0 ;
while((length= inputStream.read(buf))!=-1){
fileOutputStream.write(buf,0,length);
}
//关闭资源
fileOutputStream.close();
socket.close();
}
}
服务端(一旦客户端连接就发送一张图片给之)
public class ImageServer extends Thread {
Socket socket;
static HashSet<String> ips = new HashSet<String>(); //该集合是用户存储客户端的ip地址的。
public ImageServer(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//第三步: 获取socket输出字节流
OutputStream socketOut = socket.getOutputStream();
//第四步:获取图片的输入流,读取图片的数据,把图片数据写出给客户端
FileInputStream fileInputStream = new FileInputStream("F:\\美女\\1.jpg");
byte[] buf = new byte[1024];
int length = 0 ;
while((length = fileInputStream.read(buf))!=-1){
socketOut.write(buf,0,length);
}
String ip = socket.getInetAddress().getHostAddress(); //获取到对方的ip地址
if(ips.add(ip)){ //如果可以存储到集合中,那么就意味着这个 是一个新的IP地址。
System.out.println("恭喜:"+ ip+"同学下载图片成功!!");
System.out.println("当前下载的人数:"+ ips.size());
}
//第五步:关闭资源
fileInputStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
//第一步: 建立tcp服务端的服务
ServerSocket serverSocket = new ServerSocket(9090);
while(true){
Socket socket = serverSocket.accept(); //不断的接受用户的请求连接
new ImageServer(socket).start(); //如果产生了一个Socket,那么就意味着有一个用户与服务端连接了,那么马上开启一线程为其服务。
}
}
}
3.模拟服务器与浏览器进行通讯
浏览器与服务器之间的通讯是使用tcp协议的。
http协议是用于规范浏览器与服务器之间通讯数据的格式
服务器端(客户端就是我们的浏览器)
public class TomcatDemo extends Thread {
Socket socket ;
public TomcatDemo(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//获取socket的输出流通道
OutputStream out = socket.getOutputStream();
out.write("你好啊,浏览器!!".getBytes());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
//建立服务端的服务
ServerSocket serverSocket = new ServerSocket(9090);
//接受客户端的连接
while(true){
Socket socket = serverSocket.accept();
new TomcatDemo(socket).start();
System.out.println("用户已连接...");
}
}
}