19、网络编程(TCP和UDP)

------- android培训java培训、期待与您交流! ----------

网络编程:直接或间接的通过网络协议与其他计算机进行通讯
        准确定位一台计算机:通信双方的地址,遵循一定的规则
  ip地址:inetAddress
  本地回环地址:127.0.0.1
  主机名:localhost
  端口号:标志正在计算机上运行的进程
  端口号与ip地址组成套接字
internet上的主机有两种方式表示地址: 域名(hostName) IP地址(202.132.34.210)
   本机host所在位置:C:\Windows\System32\drivers\etc
  InetAddress的无参构造器被隐藏了,是不能调用的,只能使用InetAddress.getByName()获得ip地址
TCP和UDP
UDP
• 将数据及源和目的封装成数据包中,不需要建立连接
• 每个数据报的大小限制在64k内
• 因无连接,是不可靠协议
• 不需要建立连接,速度快
TCP
• 建立连接,形成传输数据的通道。
• 在连接中进行大数据量传输
• 通过三次握手完成连接,是可靠协议
• 必须建立连接,效率会稍低
 
Socket
Socket就是为网络服务提供的一种机制。
通信的两端都有Socket。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO传输。
 
UDP传输 的步骤:
DatagramSocket与DatagramPacket
建立发送端,接收端。
建立数据包。
调用Socket的发送接收方法。
关闭Socket。
发送端与接收端是两个独立的运行程序。
 
发送端
在发送端,要在数据包对象中明确目的地IP 及端口。
1,建立updsocket服务。
2,提供数据,并将数据封装到数据包中。
3,通过socket服务的发送(send())功能,将数据包发出去。
4,关闭资源。
DatagramSocket ds = new DatagramSocket();
byte[] by = “hello,udp”.getBytes();
DatagramPacket dp =
               new DatagramPacket(by, 0, by.length, InetAddress.getByName(“127.0.0.1”),10000);
ds.send(dp);
ds.close();
 
接收端
在接收端,要指定监听的端口。
1,定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。
    方便于明确哪些数据过来该应用程序可以处理。
2,定义一个数据包,因为要存储接收到的字节数据。
    因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3,通过socket服务的receive方法将收到的数据存入已定义好的数据包中。
4,通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。
5,关闭资源。
DatagramSocket ds = new DatagramSocket(10000);
byte[] by = new byte[1024];
DatagramPacket dp = new DatagramPacket(by,by.length);
ds.receive(dp);
String str = new String(dp.getData(),0,dp.getLength());
System.out.println(str+"--"+dp.getAddress());
ds.close();
 
例程:
UDP聊天程序,通过键盘录入获取要发送的信息,将发送和接收分别封装到两个线程中。
有收数据的部分,和发数据的部分,这两部分需要同时执行,那就需要用到多线程技术。
一个线程控制收,一个线程控制发。
因为收和发动作是不一致的,所以要定义两个run方法,而且这两个方法要封装到不同的类中。
import java.io.*;
import java.net.*;
class Send implements Runnable
{
 private DatagramSocket ds;
 public Send(DatagramSocket ds)
 {
  this.ds = ds;
 }
 public void run()
 {
  try
  {
   BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
   String line = null;
   while((line=bufr.readLine())!=null)
   {
   
    byte[] buf = line.getBytes();
    DatagramPacket dp =
     new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.255"), 10002);
    ds.send(dp);
    if("886".equals(line))
     break;
   }
  }
  catch (Exception e)
  {
   throw new RuntimeException("发送端失败");
  }
 }
}
class Rece implements Runnable
{
 private DatagramSocket ds;
 public Rece(DatagramSocket ds)
 {
  this.ds = ds;
 }
 public void run()
 {
  try
  {
   while(true)
   {
    byte[] buf = new byte[1024];
    DatagramPacket dp = new DatagramPacket(buf,buf.length);
    ds.receive(dp);
    String ip = dp.getAddress().getHostAddress();
    String data = new String(dp.getData(),0,dp.getLength());
    if("886".equals(data))
    {
     System.out.println(ip+"....离开聊天室");
     break;
    }
    System.out.println(ip+":"+data);
   }
  }
  catch (Exception e)
  {
   throw new RuntimeException("接收端失败");
  }
 }
}
class ChatDemo
{
 public static void main(String[] args) throws Exception
 {
  DatagramSocket sendSocket = new DatagramSocket();
  DatagramSocket receSocket = new DatagramSocket(10002);
  new Thread(new Send(sendSocket)).start();
  new Thread(new Rece(receSocket)).start();
 }
}
 
TCP传输
Socket和ServerSocket
建立客户端和服务器端
建立连接后,通过Socket中的IO流进行数据的传输
关闭socket
同样,客户端与服务器端是两个独立的应用程序。
 
客户端
客户端需要明确服务器的ip 地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。
连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输。
而Socket对象已经提供了输入流和输出流对象,通过getInputStream(),getOutputStream()获取即可。
与服务端通讯结束后,关闭Socket
通过Socket建立对象并指定要连接的服务端主机以及端口。
Socket s = new Socket(“192.168.1.1”,9999);
OutputStream out = s.getOutputStream();
out.write(“hello”.getBytes());
s.close();
 
服务端
服务端需要明确它要处理的数据是从哪个端口进入的。
当有客户端访问时,要明确是哪个客户端,可通过accept() 获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。
当该客户端访问结束,关闭该客户端。
建立服务端需要监听一个端口
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept ();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int num = in.read(buf);
String str = new String(buf,0,num);
System.out.println(s.getInetAddress().toString()+”:”+str);
s.close();
ss.close();
 
例程:
需求:建立一个文本转换服务器,客户端给服务端发送文本,服务单会将文本转成大写在返回给客户端。
而且客户度可以不断的进行文本转换。当客户端输入over时,转换结束。
分析:
客户端:
既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。
源:键盘录入。
目的:网络设备,网络输出流。
而且操作的是文本数据。可以选择字符流。
步骤
1,建立服务。
2,获取键盘录入。
3,将数据发给服务端。
4,后去服务端返回的大写数据。
5,结束,关资源。
都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲。
import java.io.*;
import java.net.*;
class TransClient
{
 public static void main(String[] args) throws Exception
 {
  Socket s = new Socket("192.168.1.254",10005);
                //定义读取键盘数据的流对象。
  BufferedReader bufr =
   new BufferedReader(new InputStreamReader(System.in));
  //定义目的,将数据写入到socket输出流。发给服务端。
  //BufferedWriter bufOut =
   //new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
  PrintWriter out = 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;
   
   out.println(line);
   String str =bufIn.readLine();
   System.out.println("server:"+str);
   
  }
  bufr.close();
  s.close();
 }
}
class TransServer
{
 public static void main(String[] args) throws Exception
 {
  ServerSocket ss = new ServerSocket(10005);
  Socket s = ss.accept();
  String ip = s.getInetAddress().getHostAddress();
  System.out.println(ip+"....connected");
  //读取socket读取流中的数据。
  BufferedReader bufIn =
   new BufferedReader(new InputStreamReader(s.getInputStream()));
  //目的。socket输出流。将大写数据写入到socket输出流,并发送给客户端。
  //BufferedWriter bufOut =
   //new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
  PrintWriter out = new PrintWriter(s.getOutputStream(),true);
  String line = null;
  while((line=bufIn.readLine())!=null)
  {
   System.out.println(line);
   out.println(line.toUpperCase());
// bufOut.write(line.toUpperCase());
// bufOut.newLine();
// bufOut.flush();
  }
  s.close();
  ss.close();
 }
}
该例出现的问题:客户端和服务端都在莫名的等待,为什么呢?
因为客户端和服务端都有阻塞式方法。这些方法么没有读到结束标记。那么就一直等而导致两端都在等待。

你可能感兴趣的:(java编程)