java网络程序设计初窥

java网络程序设计初窥

 

 

一、网络编程基本概念

1.OSI与TCP/IP体系模型

 

2.IP和端口

解决了文章最开始提到的定位的问题。

IP在互联网中能唯一标识一台计算机,是每一台计算机的唯一标识(身份证);网络编程是和远程计算机的通信,所以必须先能定位到远程计算机;IP帮助解决此问题;一台计算机中可能有很多进程,具体和哪一个进程进行通信,这就得靠端口来识别;

IP和端口能唯一定位到需要通信的进程。这里的IP表示地址,区别于IP协议。在OSI体系还是TCP/IP体系中,IP协议位于网际层,来封装IP地址到报文中。  

 

3.TCP和UDP协议

TCPTranfer Control Protocol 的简称,是一种 面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便 在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送 或接收操作。

UDPUser Datagram Protocol 的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。

比较:

UDP:

  1. 每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。
  2. UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。
  3. UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方

TCP:

  1. 面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中需要连接时间。
  2. TCP传输数据大小限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大的数据。
  3. TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据。

数据桢:


应用:

  • TCP 在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽,因此TCP传输的效率不如UDP高。
  • UDP 操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。

 

4.Socket

Socket是网络驱动层提供给应用程序编程接口和一种机制。我们可以把 Socket 比喻成是一个港口码头。应用程序只要把货物放到港口码头上,就算完成了货物的运送。对于接收方应用程序也要创建一个港口码头,只需要等待货物到达码头后将货物取走。

Socket 是在应用程序中创建的,它是通过一种绑定机制与驱动程序建立关系,告诉自己所对应的 IP 和 Port。在网络上传输的每一个数据帧,必须包含发送者的 IP 地址和端口号。创建完 Socket 以后,应用程序写入到 Socket 的数据,由 Socket 交给驱动程序向网络上发送数据,计算机从网络上收到与某个 Socket 绑定的 IP 和 Port 相关的数据后,由驱动程序再交给 Socket ,应用程序就可以从这个 Socket 中读取接收到的数据。网络应用程序就是这样通过 Socket 发送和接收的。

Socket数据发送过程:


Socket数据接收过程:

 

5.常用应用层协议

应用层协议是为了解决某一类应用问题,而问题的解决又往往是通过位于不同主机中的多个应用进程之间的通信和协同工作来完成的。应用层的具体内容就是规定应用进程在通信时所遵循的协议。

 

       

二、TCP通信

TCP网络程序设计是指利用Scoket类编写通信程序。
具体步骤:
            (1)服务器程序创建一个ServerSocket(服务器端套接字),调用accept()方法等待客户连接。
            (2)客户端程序创建一个Scoket,请求与服务器建立连接。
            (3)服务器接收客户的连接请求,同时创建一个新的Socket与客户建立连接。服务器继续等待新的请求。

1.InteAddress类

Java中的InetAddress是一个代表IP地址的封装。IP地址可以由字节数组和字符串来分别表示,InetAddress将IP地址以对象的形式进行封装,可以更方便的操作和获取其属性。InetAddress没有构造方法,可以通过两个静态方法获得它的对象。

// 根据主机名来获取对应的InetAddress实例

InetAddress ip = InetAddress.getByName("www.baidu.com");

// 判断是否可达 System.out.println("baidu是否可达:" + ip.isReachable(2000));

// 获取该InetAddress实例的IP字符串 System.out.println(ip.getHostAddress());

// 根据原始IP地址(字节数组形式)来获取对应的InetAddress实例

InetAddress local = InetAddress.getByAddress(new byte []{127,0,0,1}); System.out.println("本机是否可达:" + local.isReachable(5000));

// 获取该InetAddress实例对应的全限定域名

System.out.println(local.getCanonicalHostName());

2.ServerSocket(重点)

ServerSocket用来表示服务器套接字。服务器套接字通过制定的端口来等待连接的套接字,它的主要功能是等待来自网络上的连接“请求”。它可通过制定的端口来等待连接的套接字。服务器套接字可以一次与一个套接字连接。如果多台客户机同时提出连接请求,服务器套接字会将请求连接的用户机存入到队列中,然后从中取出一个套接字,与服务器新建的套接字连接起来。若请求连接数大于最大的容纳数,则多出的连接请求被拒绝。队列默认大小是50.
代码如下:

            try {
                  ServerSocket serverSocket1=new ServerSocket();//创建非绑定服务器的套接字
                  ServerSocket serverSocket2=new ServerSocket(1880);//创建绑定端口的套接字
                  ServerSocket serverSocket3 =new ServerSocket(1880,500);//创建绑定端口且指定最大长度的套接字
            } catch (IOException e) {
                  e.printStackTrace();
            }
 accept侦听并接受到此套接字的连接。此方法在进行连接之前一直阻塞。
 实例:
 
            try {
                  ServerSocket serverSocket1=new ServerSocket(1880);//创建非绑定服务器的套接字
                  System.out.println("成功创建服务器套接字");
                  System.out.println("等待客户机连接");
                  Socket socket=serverSocket1.accept();//等待与客户机连接
                  System.out.println("与客户端建立起连接");
            } catch (IOException e) {
                  e.printStackTrace();
            }
   分析:如果没有客户机请求连接,则与客户端建立起连接不会输出。

3.Socket(重点)

分析:如果没有客户机请求连接,则与客户端建立起连接不会输出。

Socket类是套接字段。
直接实例:
客户端向服务端发送信息,服务端读取客户端发送的信息,并将读取的数据写入到输出流。

服务端程序:

import java.io.*;
import java.net.*;

public class Server {
      public static void main(String[] args) {
            ServerSocket serverSocket = null; // 创建服务器端套接字
            Socket clientSocket = null; // 创建客户端套接字
            String str = null;
            DataOutputStream out = null; // 创建DataOutputStream类对象
            DataInputStream in = null; // 创建DataInputStream类对象
            try {
                  serverSocket = new ServerSocket(4331); // 实例化ServerSocket对象
                  clientSocket = serverSocket.accept(); // 接收客户的套接字连接呼叫
                  in = new DataInputStream(clientSocket.getInputStream()); // 实例化DataInputStream对象
                  out = new DataOutputStream(clientSocket.getOutputStream()); // 实例化DataOutputStream对象
                  while (true) {
                        str = in.readUTF(); // 读取客户放入连接中的信息
                        out.writeUTF("hello,我是服务器"); // 通过输出流向线路中写信息
                        out.writeUTF(str);
                        System.out.println("服务器收到:" + str);
                        Thread.sleep(1000); // 线程休眠
                  }
            } catch (Exception e) {
                  e.printStackTrace();
            }
      }
}
    客户端程序:
   
import java.io.*;
import java.net.*;

public class SocketUtill {
      public static void main(String[] args) {
            String str = null;
            Socket clientSocket; // 创建客户端套接字
            DataInputStream in = null; // 创建DataInputStream对象
            DataOutputStream out = null; // 创建DataOutputStream对象
            try {
                  clientSocket = new Socket("127.0.0.1", 4331); // 实例化Socket对象
                  in = new DataInputStream(clientSocket.getInputStream()); // 实例化DataInputStream对象
                  out = new DataOutputStream(clientSocket.getOutputStream()); // 实例化DataOutputStream对象
                  out.writeUTF("你好!!"); // 写数据
                  while (true) {
                        str = in.readUTF(); // 读取流中数据
                        out.writeUTF(((int) (Math.random() * 10) + 1) + ""); // 向流中写入0到10之间的随机数
                        System.out.println("客户端收到:" + str); // 输出信息
                        Thread.sleep(1000); // 休眠
                  }
            } catch (Exception e) {
                  e.printStackTrace();
            }
      }
}
 输出结果如图:

 

三、UDP通信

基于UDP通信的基本模式如下:
将数据打包,成为数据包,然后将数据包发往目的地。
接收别人发来的数据包,然后查看数据包。

下面是UDP程序的步骤:
发送数据包的步骤如下:

1.使用DatagramSocket()创建一个数据包套接字。
2.使用DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)创建要发送的数据包。
3.使用DatagramScoket类的send()方法发送数据包。
接收数据包步骤如下:
1.使用DatagramSocket()创建一个数据包套接字,绑定指定的端口。
2.使用DatagramPacket(byte[] buf, int length)创建字节数组来接收数据包。
3.使用DatagramPacket类的receive()方法,接收UDP包。

实例:在服务器端接收数据,再发送数据;在客户端实现发送数据,再接收数据。
服务端程序:
import java.net.*;
public class UDPServer {
public static void main(String[] args) {
      DatagramSocket serverSocket;
      try {
            serverSocket = new DatagramSocket(6000);// 创建DatagramSocket对象
            byte[] recvBuf = new byte[100]; // 创建字节数组
            DatagramPacket recvPacket = new DatagramPacket(recvBuf,
                        recvBuf.length); // 创建DatagramPacket
            serverSocket.receive(recvPacket); // 接收数据报
            String recvStr = new String(recvPacket.getData(), 0, recvPacket
                        .getLength());
            System.out.println("Hello!" + recvStr);
            int port = recvPacket.getPort(); // 获取接收端口
            InetAddress address = recvPacket.getAddress(); // 创建InetAddress实例
            String sendStr = "服务器发送的信息";
            byte[] sendBuf;
            sendBuf = sendStr.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuf,
                        sendBuf.length, address, port); // 创建数据包
            serverSocket.send(sendPacket); // 发送数据包
            serverSocket.close(); // 关闭DatagramSocket对象
      } catch (Exception e) {
            e.printStackTrace();
      }
}
}
    客户端程序:
   
import java.io.*;
import java.net.*;

public class UDPClient {
      public static void main(String[] args) {
            DatagramSocket clientSocket;
            try {
                  clientSocket = new DatagramSocket();// 创建套接字对象
                  String sendStr = "你好,我是客户机";
                  byte[] sendBuf;
                  sendBuf = sendStr.getBytes();
                  InetAddress addr = InetAddress.getByName("127.0.0.1");
                  int port = 6000; // 指定端口
                  DatagramPacket sendPacket = new DatagramPacket(sendBuf,
                              sendBuf.length, addr, port); // 创建数据包
                  clientSocket.send(sendPacket); // 发送数据包
                  byte[] recvBuf = new byte[100];
                  DatagramPacket recvPacket = new DatagramPacket(recvBuf,
                              recvBuf.length); // 创建数据包对象
                  clientSocket.receive(recvPacket); // 接收信息
                  String recvStr = new String(recvPacket.getData(), 0, recvPacket
                              .getLength());
                  System.out.println("收到:" + recvStr);
                  clientSocket.close();
            } catch (Exception e) {
                  e.printStackTrace();
            }
      }

}
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值