黑马程序员 java基础之网络编程TCP


TCP网络传输。

客户端和服务端

 

分别对应着两个对象。

Scoket(客户端)和ServerSocket(服务端)。

 

  Socket(String  address, int port)

          创建一个流套接字并将其连接到指定 IP 地址的指定端口号。

这个客户端在一建立的情况下就去连接服务端。

通过指定地址和指定的端口找到服务端。并与之建立连接。

 

步骤:
1.创建Socket服务,并指定要连接的主机和端口。

   Socket s = new Socket("localhost",10002);

   如果上述这步成功了的话。也就是通路建立了。

当通路一建立,就有一个Socket流,也就是网络流。

两端之间建立了一个网络流。Socket中既有输入流也有输出流,

一旦建立连接,在Socket中就可以取到输入流和输出流对数据进行操作。

 

流不用去建立,只要通路一建立,流就存在了。

 

getOutputStream()

         返回此套接字的输出流。

getInputStream()

         返回此套接字的输入流。

 

服务端

 

服务端没有自己的流对象。

服务端和客户端连接的时候,就使用了客户端的流对象和客户端进行操作。

 

public classTCPSocket {

 

      /**

       *@param args

       */

      public static void main(String[] args)throws Exception

      {

          

           Socket s = newSocket("localhost",10002);

           //为了发送数据,应该获取socket流中的输出流

           OutputStream os =s.getOutputStream();

          

           BufferedWriter bw = newBufferedWriter(new OutputStreamWriter(os));

 

           bw.write("tcp,gemenwolaile");

           bw.flush();

           //而在这里不同去关流

           s.close();

          

      }

 

}

 

/*

 * 需求:定义端点接收数据并打印在控制台上。

 * 服务端:

 * 1.建立服务端的Socket服务。通过ServerSocket类去建立。

 * 一旦建立,并监听一个端口。

 * 2.获取链接过来的客户端对象。

 *   通过ServerSocket的accept方法去获得。所以这个方法是阻塞式。

 * 3.客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端

 * 的读取流来读取发过来的数据。并打印在控制台。

 * 4.关闭服务端。(可选)

 * 

 * */

class TcpServer

{

      public static void main(String[] args)throws Exception

      {

          

           //建立服务端Socket服务,并监听一个端口。

           ServerSocket ss  = new ServerSocket(10002);

           //通过accept方法获取连接过来的客户端对象。

           Socket s = ss.accept();

          

           System.out.println(s.getInetAddress().getHostAddress());

           //获取客户端发送过来的数据,那么要使用客户端对象的读取流方法来读取数据。

          

           InputStream in = s.getInputStream();

          

           byte[] buf = new byte[1024];

          

           int len = in.read(buf);

          

           System.out.println(newString(buf,0,len));

          

     

           s.close();//关闭客户端。

          

          

          

      }

     

 

}

 

必须先启动服务端。

 

 

 

演示tcp传输的客户端和服务端的互访。

需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。

 

/*

 1.建立socket服务。指定要连接的主机和端口

 2.获取socket流中的输出流,将数据写到该流中。通过网络发送给服务端。

 3.获取socket流中的输入流,将服务器反馈的数据获取到,并打印。

 4.关闭客户端资源。

 */

 

class TcpClient2

{

      public static void main(String[] args)throws Exception

      {

           Socket s =  new Socket("localhost",10004);

           OutputStream os = s.getOutputStream();

           os.write("nihao".getBytes());

          

           InputStream is = s.getInputStream();

          

           byte [] arr = new byte[1024];

           //十分要主要,这里的read读的是Socket流。也是一个阻塞式方法。只有服务端往回发送数据的时候,才会解除阻塞。

           int len = is.read(arr);

          

           System.out.println(newString(arr,0,len));

           s.close();

     

          

      }

}

class TcpServer2

{

      public static void main(String[] args)throws Exception

      {

           ServerSocket ss = newServerSocket(10004);

          

           Socket s = ss.accept();

           InputStream is = s.getInputStream();

          

           byte [] arr = new byte[1024];

           int len = is.read(arr);

          

           System.out.println(newString(arr,0,len));

          

           OutputStream os =s.getOutputStream();

           os.write("完成".getBytes());

          

           s.close();

          

          

          

          

      }

}

 

 

 

 

package day5;

importjava.net.*;

importjava.io.*;

public classTCPSocket2 {

 

     

      public static void main(String[] args) {

           // TODO Auto-generated method stub

 

      }

 

}

 

 

class Client3

{

 

      public static void main(String[] args)throws Exception

      {

           Socket s = newSocket("localhost",10009);

          

           BufferedWriter bw = new BufferedWriter(newOutputStreamWriter(s.getOutputStream()));

          

           BufferedReader br = newBufferedReader(new InputStreamReader(System.in));

           String ss = null;

          

           BufferedReader brr = newBufferedReader(new InputStreamReader(s.getInputStream()));

           while((ss = br.readLine())!=null)

           {

                 bw.write(ss);

                 bw.newLine();

                 bw.flush();

                

           System.out.println(brr.readLine());

     

           }

          

          

           br.close();

           s.close();

          

                

          

      }

}

class Server3

{

 

      public static void main(String[] args)throws Exception

      {

           ServerSocket ss = newServerSocket(10009);

          

           Socket s = ss.accept();

           InputStream is = s.getInputStream();

          

           BufferedReader br = newBufferedReader(new InputStreamReader(is));

          

           OutputStream os =s.getOutputStream();

           BufferedWriter bw = new BufferedWriter(newOutputStreamWriter(os));

           String sss  = null;

           while((sss = br.readLine())!=null)

           {

                 //上边的readLine只有在看到回车符后才能结束,也就是解除阻塞。

          

                

          

           bw.write(sss.toUpperCase());

           bw.newLine();

           bw.flush();

           }

          

           //有一个疑问,为什么当客户端结束的时候,服务端也结束了,

           //这是因为,当客户端调用s.close()时,会在流里写一个-1,

           //然后服务器端就跳出循环,然后通过ss关闭服务器。

           ss.close();

          

          

          

          

      }

}

 

要注意,对于读取流中的阻塞式方法来说,一定要将发送发的缓冲区刷新。

而且必须将行结束符写到这个流中。

 

对于服务器端的阻塞式方法,如readLine(),必须在客户端发送一个标志,让服务器端知道其结束了,否则服务器一直处于读取数据的状态。

在客户端使用

s.shutdownOutput();//关闭客户端的输出流,相当于给流中加入一个结束标记

 

 

下边,我们使用更高级的协议去完成一个自定义浏览器和tomcat服务器的处理请求。

可以直接使用应用层的协议去封装。

URL url = newURL("http://localhost:8080/GP2/index.jsp");

//首先将url地址封装到一个对象为URL中。

URLConnectionconn = url.openConnection();

//这个URLConnection就封装了有关底层协议的一些信息。

//也就通过一些应用层的协议进行拆包,并将这些属性封装到这个对象中去.

//然后通过openConnection()在内部帮助我们去完成Socket等一系列连接动作。

//所以不同写Socket(是在传输层上的协议),而且是带着协议去封装的。

 

 

//当连接成功,当然可以将其服务端传递过来的数据拿到。也就是得到输入流对象。

从获取值

InputStream is =conn.getInputStream();

 

//从而从这个流对象中的得到值

byte [] arr =new byte[1024];

          

           int len = 0;

           while((len = is.read(arr))!=-1)

           {

                 System.out.println(newString(arr,0,len));

                

           }

 

这时候传递过来的数据就没有了响应头。而直接打出html中的信息。

这是因为。当底层的网络协议把数据封装好之后(包括响应头),通过应用层去拆包之后,将数据和响应头分离开来,得到的数据就只剩数据了。

而这些响应头中的信息,可以通过URLConnection对象中的一系列方法进行简析.

比如说:System.out.println(conn.getHeaderField("Server"));

可以得到有关服务器的信息。

当浏览器写入一个网址之后,去访问某一台主机的时候.它到底做什么了事情?

 在上网的时候,先去本地找hosts中的各自域名的映射关系.

当本地有,就返回本地的,如localhost,如果本地没有,就去各自运营商提供的域名服务器DNS中去寻找映射关系,最后使用ip地址找到对应的服务器,使用端口找到对应的应用程序.如果直接输入ip地址,则不走域名简析.

 

 

 

转载于:https://www.cnblogs.com/xiewen3410/archive/2013/05/14/3078647.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值