黑马程序员----java基础--网络编程(1)(3)
三、TCP协议-客户端和服务端
客户端Client)首先与服务端Server)建立连接,形成通道其实就是IO流),然后,数据就可以在通道之间进行传输,并且单个Server端可以同时与多个Client端建立连接。Socket和ServerSocket,建立客户端和服务器端。建立连接后,通过Socket中的IO流进行数据的传输。关闭socket。同样,客户端与服务器端是两个独立的应用程序。
TCP客户端
客户端需要明确服务器的ip地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通过getInputStream()和getOutputStream()获取即可与服务端通讯。结束后关闭Socket。客户端,通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。因为tcp是面向连接的。所以在建立socket服务时,就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。
TCP服务端
服务端需要明确它要处理的数据是从哪个端口进入的。当有客户端访问时,要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。当该客户端访问结束,关闭该客户端。1,建立服务端的socket服务。ServerSocket();并监听一个端口。2,获取连接过来的客户端对象。通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。并打印在控制台。4,关闭服务端。可选)。
TCP协议因为是面向连接的。所以传输数据必须先开服务端,再开客户端。否则,客户端根本连接不上服务端。
1、Socket类中常用方法
(1)、构造方法
1 new Socket();
2 new Socket(InetAddress address,int port);//创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
3 new Socket(String host,int port);// 创建一个流套接字并将其连接到指定主机上的指定端口号。
(2)、成员方法
- void bind(SocketAddress bindpoint);//将套接字绑定到本地地址。
- void connect(SocketAddress endpoint);//将此套接字连接到服务器。
- InetAddress getInetAddress();//返回套接字连接的地址。
- InputStream getInputStream();//返回此套接字的输入流。
- OutputStream getOutputStream();// 返回此套接字的输出流。
- int getPort();// 返回此套接字连接到的远程端口
- void shutdownInput();// 此套接字的输入流置于“流的末尾”。
- void shutdownOutput();// 禁用此套接字的输出流
2、ServerSocket类中常用方法
(1)、构造方法
1 new ServerSocket();//创建非绑定服务器套接字。
2 new ServerSocket(int port);//创建绑定到特定端口的服务器套接字。
(2)、成员方法
1 Socket accept();//侦听并接受到此套接字的连接。
2 InetAddress getInetAddress();// 返回此服务器套接字的本地地址。
需求:TCP协议-服务端和客户端交互代码演示:
- import java.io.*;
- import java.net.*;
- class TCPClient
- {
- public static void main(String[] args) throws Exception
- {
- //创建客户端的socket服务。指定目的主机和端口
- Socket s=new Socket("192.168.1.100",5544);
- //为了发送数据,应该获取socket流中的输出流。
- OutputStream out=s.getOutputStream();
- out.write("TCP,我来了!".getBytes());
- 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 TCPServer
- {
- public static void main(String[] args)throws Exception{
- //建立服务端socket服务。并监听一个端口。
- ServerSocket ss=new ServerSocket(5544);
- //通过accept方法获取连接过来的客户端对象。
- Socket s=ss.accept();
- //获取ip地址
- String ip=s.getInetAddress().getHostAddress();
- System.out.println(ip+".....connnect");
- //获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
- InputStream in=s.getInputStream();
- byte[] buf=new byte[1024];
- int len=in.read(buf);
- System.out.println(new String(buf,0,len));
- OutputStream out=s.getOutputStream();
- out.write("收到".getBytes());
- ss.close();
- //关闭客户端.
- s.close();
- }
- }
需求:建立一个文本转换服务器。
客户端给服务端发送文本,服务单会将文本转成大写在返回给客户端。而且客户度可以不断的进行文本转换。当客户端输入over时,转换结束。
客户端:
既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。
源:键盘录入。
目的:网络设备,网络输出流。
而且操作的是文本数据。可以选择字符流。
步骤
1,建立服务。
2,获取键盘录入。
3,将数据发给服务端。
4,后去服务端返回的大写数据。
5,结束,关资源。
都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲。
服务端:
源:socket读取流。
目的:socket输出流。
都是文本,装饰。
- import java.io.*;
- import java.net.*;
- class TransClient
- {
- public static void main(String[] args) throws Exception
- {
- Socket s=new Socket("192.168.1.100",7788);
- //定义读取键盘数据的流对象。
- BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
- //定义目的,将数据写入到socket输出流。发给服务端。
- PrintWriter out=new PrintWriter(s.getOutputStream(),true);
- //定义一个socket读取流,读取服务端返回的大写信息。
- BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
- String line=null;
- while ((line=br.readLine())!=null)
- {
- out.println(line);
- if("over".equals(line))
- break;
- String info=in.readLine();
- System.out.println("info="+info);
- }
- s.close();
- }
- }
- class TransServer
- {
- public static void main(String[] args)throws Exception{
- ServerSocket ss=new ServerSocket(7788);
- Socket s=ss.accept();
- System.out.println(s.getInetAddress().getHostAddress()+".....connect");
- //读取socket读取流中的数据。
- BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
- //目的。socket输出流。将大写数据写入到socket输出流,并发送给客户端。
- PrintWriter out=new PrintWriter(s.getOutputStream(),true);
- String line=null;
- while ((line=in.readLine())!=null)
- {
- System.out.println(line);
- out.println(line.toUpperCase());
- if("over".equals(line))
- break;
- }
- s.close();
- ss.close();
- }
- }
需求:TCP协议上传文本文件
- import java.io.*;
- import java.net.*;
- class TCPClient
- {
- public static void main(String[] args)throws Exception
- {
- Socket s=new Socket("192.168.1.100",9999);
- BufferedReader br=new BufferedReader(new FileReader("TCPDemo.java"));
- PrintWriter out=new PrintWriter(s.getOutputStream(),true);
- BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
- String line=null;
- while ((line=br.readLine())!=null)
- {
- out.println(line);
- }
- s.shutdownOutput();//关闭客户端的输出流。相当于给流中加入一个结束标记-1.
- System.out.println(in.readLine());
- s.close();
- br.close();
- }
- }
- class TCPServer
- {
- public static void main(String[] args)throws Exception{
- ServerSocket ss=new ServerSocket(9999);
- Socket s=ss.accept();
- System.out.println(s.getInetAddress().getHostAddress()+"....connect");
- BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
- PrintWriter pw=new PrintWriter(new FileWriter("E:\\TCPDemo.java"),true);
- PrintWriter out=new PrintWriter(s.getOutputStream(),true);
- String line=null;
- while ((line=in.readLine())!=null)
- {
- pw.println(line);
- }
- out.println("上传成功");
- s.close();
- ss.close();
- pw.close();
- }
- }
需求:TCP客户端并发上传图片代码演示:
服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。
如何定义线程呢?
只要明确了每一个客户端要在服务端执行的代码即可。将该代码存入run方法中。
- import java.io.*;
- import java.net.*;
- class PicClient
- {
- public static void main(String[] args)throws Exception{
- File file=new File(args[0]);
- if(!(file.exists()&& file.isFile())){
- System.out.println("请上传图片");
- return;
- }
- if(!(file.getName().endsWith(".jpg"))){
- System.out.println("上传格式错误");
- return;
- }
- if(file.length()>=1024*1024*4){
- System.out.println("文件过大,请切割后上传");
- return;
- }
- Socket s=new Socket("192.168.1.104",5555);
- FileInputStream fis=new FileInputStream(file);
- OutputStream out=s.getOutputStream();
- byte[] buf=new byte[1024];
- int len=0;
- while ((len=fis.read(buf))!=-1)
- {
- out.write(buf,0,len);
- }
- s.shutdownOutput();//告诉服务端数据已写完
- InputStream in=s.getInputStream();
- byte[] bufIn=new byte[1024];
- int num=in.read(bufIn);
- System.out.println(new String(bufIn,0,num));
- s.close();
- fis.close();
- }
- }
- class PicThread implements Runnable
- {
- private Socket s;
- PicThread(Socket s){
- this.s=s;
- }
- public void run(){
- String ip=s.getInetAddress().getHostAddress();
- System.out.println(ip+".....connect");
- try
- {
- int count=1;
- //创建file对象
- File file=new File("E:\\"+ip+"("+count+")"+".jpg");
- //如果file文件存在则count++,直到不存在为止
- while(file.exists())
- file=new File("E:\\"+ip+"("+(count++)+")"+".jpg");
- InputStream in=s.getInputStream();
- FileOutputStream fos=new FileOutputStream(file);
- byte[] buf=new byte[1024];
- int len=0;
- while ((len=in.read(buf))!=-1)
- {
- fos.write(buf,0,len);
- }
- OutputStream out=s.getOutputStream();
- out.write("上传成功".getBytes());
- s.close();
- }
- catch (Exception e)
- {
- System.out.println(ip+"连接成功");
- }
- }
- }
- class PicServer
- {
- public static void main(String[] args)throws Exception{
- ServerSocket ss=new ServerSocket(5555);
- while (true)
- {
- Socket s=ss.accept();
- new Thread(new PicThread(s)).start();
- }
- }
- }
需求:客户端通过键盘录入用户名。服务端对这个用户名进行校验。最多就登录三次。
如果该用户存在,在服务端显示xxx,已登陆。
并在客户端显示 xxx,欢迎光临。
如果该用户不存在,在服务端显示xxx,尝试登陆。
并在客户端显示 xxx,该用户不存在。
- import java.io.*;
- import java.net.*;
- class LoginClient
- {
- public static void main(String[] args)throws Exception
- {
- Socket s=new Socket("192.168.1.104",6666);
- BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
- //读取socket流中的读取流
- BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
- //socket流中的输出流
- PrintWriter out=new PrintWriter(s.getOutputStream(),true);
- //循环3次输入,如果输入为null,直接停止输入
- for (int x=0;x<3 ;x++ )
- {
- String name=br.readLine();
- if(name==null)
- break;
- out.println(name);
- String info=in.readLine();
- System.out.println(info);
- //如果获取到流中有“欢迎“字样,说明对方已经登录,这时候即使输入的不到3次,也停止输入,因为已经登录成功了。
- if(info.contains("欢迎")){
- break;
- }
- }
- s.close();
- }
- }
- class LoginThread implements Runnable
- {
- private Socket s;
- LoginThread(Socket s){
- this.s=s;
- }
- public void run(){
- String ip=s.getInetAddress().getHostAddress();
- System.out.println(ip+".....connect");
- try
- {
- for (int x=0;x<3 ;x++ )
- {
- //读取socket流中的输入流
- BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
- String name=in.readLine();
- if(name==null)
- break;
- //读取文件
- BufferedReader br=new BufferedReader(new FileReader("Userinfo.txt"));
- //socket流输出流
- PrintWriter out=new PrintWriter(s.getOutputStream(),true);
- //定义一个标记, 从socket输入流中的键盘数据判断user.txt中是否有name符合,如果有标记为真,跳出while循环。
- boolean flag=false;
- String line=null;
- while ((line=br.readLine())!=null)
- {
- //判断Userinfo.txt和name是否有相同的
- if(line.equals(name)){
- flag=true;
- break;
- }
- }
- if(flag){
- System.out.println(name+",已登陆");
- out.println(name+",欢迎光临");
- break;
- }
- else{
- System.out.println(name+",尝试登陆");
- out.println(name+",该用户不存在");
- }
- }
- s.close();
- }
- catch (Exception e)
- {
- System.out.println(ip+"连接失败");
- }
- }
- }
- class LoginServer
- {
- public static void main(String[] args)throws Exception{
- ServerSocket ss=new ServerSocket(6666);
- while (true)
- {
- Socket s=ss.accept();
- new Thread(new LoginThread(s)).start();
- }
- }
- }

用户点评