黑马程序员---网络编程(TCP传输)

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

简介
UDP分为发送端和接受端
TCP分为客户端和服务器端(Socket和ServerSocket)
建立连接后
TCP三次握手的过程如下:
客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。
服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。
客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。
三次握手完成,TCP客户端和服务器端成功地建立连接,可以开始传输数据了。

下面演示TCP传输的客户端和服务器端的互访
客户端发送数据给服务器端,服务器端接受数据后给客户端反馈信息

服务器端

package fourth;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *服务器端:
 *1.创建服务器端的Socket服务,ServerSocket,并监听一个端口
 *2.获取连接过来的客户端对象,通过ServerSocket的accept完成,这个方法是阻塞式的,如果没有连接就等待
 *3.客户端如果发送过来数据,那么服务器端要使用对应的客户端对象,并获取到该客户端对象的读取流来获取数据
 *4.关闭服务器(可选操作)
 *
 *定义服务器端,接受数据并打印在控制台上
 */
public class TcpServer2 {
    public static void main(String[] args) {
        try {
            //建立服务端的Socket服务,并监听一个端口
            ServerSocket ss=new ServerSocket(10004);
            //通过accept获取客户端的发送数据
            Socket s=ss.accept();
            String ip=s.getInetAddress().getHostAddress();
            System.out.println(ip+".....connected");
            //获取数据
            InputStream is=s.getInputStream();
            OutputStream out=s.getOutputStream();
            byte[]b=new byte[1024];
            int len=is.read(b);
            System.out.println(new String(b,0,len));
            out.write("收到了,".getBytes());
            s.close();//结束连接
            ss.close();//可选的
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端

package fourth;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

/**
 *客户端:
 *给服务器端发送一个文本数据
 *1.创建Socket服务,并指定要连接的主机和端口
 *2.获取Socket服务中的输出流,将数据写到流中,通过网络发送给服务器
 *3.获取Socket服务中的输入流,获取服务器的反馈数据并打印
 *4,关闭资源
 *
 */
public class TcpClient2 {
    public static void main(String[] args) {
        try {
            //创建Socket服务,并指定要连接的主机和端口
            Socket s=new Socket(InetAddress.getLocalHost(), 10004);
            //为了发送数据,应该获得Socket流中的输出流
            OutputStream out=s.getOutputStream();
            out.write("Hello TCPClient".getBytes());
            InputStream is=s.getInputStream();
            byte[]b=new byte[1024];
            int len=is.read(b);
            System.out.println(new String(b,0,len));
            s.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注:一定要先启动服务器端,不然先启动客户端会报java.net.ConnectException异常

下面这个练习实现了服务器端的文本转换功能,把客户端的文本数据转成大写在返回
服务器端

package fourth;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
 *需求:建立一个文本转换服务器
 *客户端给服务器端发送文本,服务器端把文本转换为大写返回给客户端
 *而且客户端可以不断进行文本转换,当客户端输入over时结束
 *
 *分析
 *客户端:
 *既然是在设备上操作数据,就可以用IO技术,并按照IO的操作规则来思考
 *源:键盘录入
 *目的:网络设备,网络输出流
 *操作的是文本数据,可以使用字节流,同时提高效率加入缓冲
 *服务器端
 *源:Socket读取流
 *目的:Socket输出流
 *都是文本,
 */
public class TransServer {
    public static void main(String[] args) {
        try {
            ServerSocket ss=new ServerSocket(10005);
            Socket s=ss.accept();
            //读取Socket流中的数据
            BufferedReader brIn=new BufferedReader(
                    new InputStreamReader(s.getInputStream()));
            //目的,Socket输出流,将大写数据写入到Socket输出流发送给客户端
//          BufferedWriter bwOut=new BufferedWriter(
//                  new OutputStreamWriter(s.getOutputStream()));
            PrintWriter out=new PrintWriter(s.getOutputStream(),true);
            String line=null;
            while((line=brIn.readLine())!=null){
//              bwOut.write(line.toUpperCase());
//              bwOut.newLine();
//              bwOut.flush();
                out.println(line);
            }
            s.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端

package fourth;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 *
 *步骤
 *1.建立服务
 *2.获取键盘录入
 *3.将数据发给服务器端
 *4.获取服务器端返回数据,打印到控制台
 *5,关闭资源
 *
 */


public class TransClient {
    public static void main(String[] args) {
        try {
            Socket s=new Socket(InetAddress.getLocalHost(), 10005);
            //获取键盘数据
            BufferedReader br=
                    new BufferedReader(new InputStreamReader(System.in));
            //定义目的,将数据写入Socket流发给服务器端
//          BufferedWriter bwOut=new BufferedWriter(
//                  new OutputStreamWriter(s.getOutputStream()));
            PrintWriter out=new PrintWriter(s.getOutputStream(),true);
            //定义一个Socket读取流,读取服务器端返回信息
            BufferedReader brIn=new BufferedReader(
                    new InputStreamReader(s.getInputStream()));
            String line=null;
            while((line=br.readLine())!=null){
                if("over".equals(line))
                    break;
//              bwOut.write(line);
//              bwOut.newLine();
//              bwOut.flush();
                out.println(line);
                System.out.println("server :: "+brIn.readLine());
            }


        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

注:上边两个程序有几行被注释了,那是被下边一行代码给替换了,它们都能成功

可能出现的问题,客户端和服务器端都在莫名的等待,这事因为它们都有阻塞式方法,可能的原因是这个方法没有读到结束标记,就一直在等
即bwOut.newLine();bwOut.flush();这两句代码被忽略是会出现这种情况

下面写一个上传文件的程序
服务器端

package fourth;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TextServer {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(10006);
            Socket s=ss.accept();
            BufferedReader brIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
            PrintWriter pw=new PrintWriter(new FileWriter("D:\\info.txt"));
            String line=null;
            while((line=brIn.readLine())!=null){
                if (line.equals("over")) {
                    break;
                }
                pw.println(line);
            }
            PrintWriter out=new PrintWriter(s.getOutputStream());
            out.println("上传成功");
            out.close();
            s.close();
            ss.close();


        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端

package fourth;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

public class TextClient {
    public static void main(String[] args) {
        try {
            Socket s = new  Socket(InetAddress.getLocalHost(),10006);
            BufferedReader br =new BufferedReader(new FileReader("E:\\info.txt"));
            PrintWriter out=new PrintWriter(s.getOutputStream(),true);
            String line=null;
            while((line=br.readLine())!=null){
                out.println(line);
            }
            s.shutdownOutput();//关闭客户端输出流,相当于加入结束标记
            BufferedReader brIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
            System.out.println(brIn.readLine());
            s.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

over,主要注意s.shutdownOutput();结束标记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值