一,TCP通信
在UPD通信分成发送端和接收端,而在TCP协议中则分成客户端和服务端。客户端对应的对象时Socket,服务端对应的对象时ServerSocket。客户端一建立就会去寻找服务端,原因正是因为TCP是面向连接的,所以Socket一建立服务必须要有服务端存在,并连接成功。形成通道后在该通道进行数据传输。
(TCP/IP通信协议的特点在网络编程UDP中已经做过详细的概述)
1,TCP通信客户端和服务端的基本建立方法:
需求:创建客户端和服务端,客户端连接上服务端后,向服务端发送一个数据。
(1)需求:定义客户端,发送数据到服务端.
步骤:
1,创建Socket服务,并指定要连接的主机和端口;
2,为了发送数据,应该获取Socket流中的输出流发送数据。
import java.io.*;
import java.net.*;
class TcpClient
{
public static void main(String[] args) throws Exception {
//创建Socket服务,指定主机和端口
Socket s = new Socket("127.0.0.1",10060);
//获取该Socket的输出流,传输数据
OutputStream os = s.getOutputStream();
os.write("嗨,你好。。。。".getBytes());
//关闭客户端
s.close();
}
}
(2)需求:定义服务端接收数据并打印,在控制台上;
步骤:
1,创建服务端的ServerSocket服务,并监听某个接口
2,获取连接过来的客户端对象,通过accept方法,没有连接就会等待,知道有客户端链接过来,它是一个阻塞式方法;
3,客户端发送过来数据,那么服务端使用对应的客户端对象,获取该对象的读取流读取数据并打印在控制台上。
4,关闭服务端,可选项。
class TcpServer
{
public static void main(String[] srgs) throws Exception{
//创建Serversocket服务,监听10060端口
ServerSocket ss = new ServerSocket(10060);
//获取连接过来的客户端对象,用accept方法
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip);
//获取该对象的读取流
InputStream in = s.getInputStream();
byte[] by = new byte[1024];
int len = 0;
len = in.read(by);
String str = new String(by,0,len);
System.out.println(str);
s.close();//关闭客户端
}
}
2,在上面的程序中只是客户端发送一个数据到服务端,服务单接受了,但是并没有给客户端一个反馈信息,如何能够在服务端接受客户端数据后给服务端一个反馈信息呢?
无论是客户端还是服务端,当得到Socket对象后,该对象就可以获取到Socket中的输入流和输出流,通过getInputStream()和getOutputStream(),然后我们就可以通过流来进行客户端和服务端之间的数据传输了。
需求:创建客户端和服务端,当客户端连接上服务端后,向服务端发送一个数据,服务端接收到数据后给客户端一个反馈。
import java.io.*;
import java.net.*;
class TcpSend2
{
public static void main(String[] args) throws Exception {
Socket s = new Socket("100.64.174.174",10050);
//获取Socket对象的输出流,给服务端发送数据
OutputStream out = s.getOutputStream();
out.write("客户端,你好。".getBytes());
//获取Socket对象的输入流,接受服务端发送过来的数据
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
class TcpServer2
{
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10050);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "....已连接");
//获取Socket对象的输入流,接受客户端发送过来的数据
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
//获取Socket对象的输出流,发送数据给客户端
OutputStream out = s.getOutputStream();
Thread.sleep(6000);
out.write("收到服务端数据。。。".getBytes());
s.close();
ss.close();
}
}
3,客户端和服务端的交互
需求:实现客户端向服务端发送数据,服务端接收到数据后将数据转换成大写发送到客户端,客户端将数据打印到控制台;当客户端发送的数据是over时,结束服务;
分析:
客户端是在设备上操作数据,那么可以用到IO流的规律来思考问题
源:键盘录入操作的是:字符,用字符流客户端能获取的是Socket中的字字节流,要用到字节流转化成字符流要提高读取的效率,要用到缓冲区,所以:BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in))
目的:网络输出流
思路:
1,建立Socket服务连接服务端
2,获取键盘输入
3,将数据发送给服务端
4,等待服务端返回数据
5,关闭服务端
import java.io.*;
import java.net.*;
class TcpSend3
{
public static void main(String[] args) throws Exception {
Socket s = new Socket("100.64.174.174",10080);
//获取键盘录入
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//获取Socket中的输出流
// BufferedWriter bufOut = new
//BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//可以采用目的输出流,即可以接收输入流,也可以接收输出流,并且可以自动换行和刷新
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
//获取Socket中的读取流,读取服务端返回的大写数据
BufferedReader bufIn = new
BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while ((line = bufr.readLine())!=null)
{
if("over".equals(line))
break;
pw.println(line);
// bufOut.write(line);//此处只是将字符串写入到输出流中没有换行标志,
//服务端没看到回车键,所以服务端会以为数据没有写完,会一直等待
// bufOut.newLine();
// bufOut.flush();
//读取服务端返回的大写数据
String in = bufIn.readLine();//readLine方法只有在读取到结束标志即回车符时才会返回字符
System.out.println("服务端返回的数据是: " + in );
}
bufr.close();
s.close();
}
}
class TcpServer3
{
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10080);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + ".....连接成功" + "\n");
//获取Socket的输入流,接收数据,以转换成客户想要的结果
BufferedReader bufIn = new
BufferedReader(new InputStreamReader(s.getInputStream()));
//获取Socket的输出流,将数据转换后发送给客户
// BufferedWriter bufOut = new
// BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
String line = null;
while ((line = bufIn.readLine())!=null)
{
System.out.println("客户端的数据是: " + line);
pw.println(line.toUpperCase());
// bufOut.write(line.toUpperCase());
// bufOut.newLine();//如果不给出一个换行符,客户端接收数据时由于是单行读取,只有碰到回车符时才认为是
//读取结束,否则会处于一直等待;
// bufOut.flush();
}
s.close();
ss.close();
}
}
4 ,需求:创建客户端和服务端,通过 TCP 协议实现客户端享服务端上传文本文件。
import java.io.*;
import java.util.*;
import java.net.*;
class UpClient
{
public static void main(String[] args) throws Exception {
Socket s = new Socket("127.0.0.1",10000);
//客户端读取文件的源是硬盘,并且操作的是文本文件,读取字符串需要缓冲区
BufferedReader bufr = new BufferedReader(new FileReader("server.txt"));
//获取Socket服务流,为了便于打印和输出数据,将其包装成方便操作字符的流。
InputStream in = s.getInputStream();
Scanner scanner = new Scanner(in);
OutputStream out = s.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out),true);
//循环读取硬盘的文件内容写入到输出流
String line = "";
while((line = bufr.readLine())!=null) {
pw.println(line);
}
//关闭Socket输出流,给对方一个文本结束标记
s.shutdownOutput();
//获取服务端的反馈信息
while(scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
in.close();
}
}
class UpServer
{
public static void main(String[] args) throws Exception {
//创建服务器套接字,绑定到端口10000
ServerSocket ss = new ServerSocket(10000);
Socket s = ss.accept();
//获取客户端IP地址
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "连接成功 ");
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
//创建打印流,在指定目录创建一个文件
PrintWriter pw = new PrintWriter(new FileWriter("C://server.java"),true);
BufferedReader bufr = new BufferedReader(new InputStreamReader(in));
//从输入流中读取内容,写入创建的文件
String line = "";
while((line = bufr.readLine())!=null) {
pw.println(line);
}
pw.close();
//给客户端一个反馈信息
PrintWriter pw2 = new PrintWriter(new OutputStreamWriter(out));
pw2.println("上传成功!");
pw2.close();
}
}
5 ,需求:创建客户端和服务端,使用 TCP 协议从客户端上传一张图片文件给服务端,服务端接收完毕后给客户端一个反馈信息。(原理和上传文本文件一样,只需要将上述示例的字符流换成字节流即可)
import java.io.*;
import java.net.*;
class PicClient
{
public static void main(String[] args) throws Exception {
//创建服务,连接到指定地址和端口
Socket s = new Socket("100.64.174.174",10010);
//创建文件输入流
FileInputStream fi = new FileInputStream("1.jpg");
//读取图片数据,写入到Socket的输出流
OutputStream out =s.getOutputStream();
int len = 0;
byte[] buf = new byte[1024];
while ((len = fi.read(buf))!=-1)
{
out.write(buf,0,len);
}
//关闭输出流,告诉服务端数据写入结束
s.shutdownOutput();
//获取服务端反馈信息
InputStream in = s.getInputStream();
byte[] b = new byte[1024];
int num = in.read(b);
System.out.println(new String(b,0,num));
//关闭流
fi.close();
s.close();
}
}
class PicServer
{
public static void main(String[] args) throws Exception {
//建立服务端,绑定到本地10010端口
ServerSocket ss = new ServerSocket(10010);
Socket s = ss.accept();
//获取链接成功的客户端IP地址
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "已连接");
//获取Socket输入流,并且创建图片文件,将流中的数据写入到图片中
InputStream in = s.getInputStream();
FileOutputStream fo = new FileOutputStream("server.jpg");
int len = 0;
byte[] buf = new byte[1024];
while ((len = in.read(buf))!=-1)
{
fo.write(buf,0,len);
}
//给客户端一个反馈信息
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
out.flush();
//关闭流
fo.close();
ss.close();
}
}