网络编程(java就业培训教程)笔记

网络编程

tcp/ip协议中,ip地址用4个字节,也就是32位的二进制来表示,称为ipv4

Ip地址只能保证把数据送到该计算机,但不能保证把这些数据交给那个网络程序,因此,每个发送的网络数据包的头部都含有一个被称为“端口”的部分,它是一个整数,用于表示该数据帧交给那个应该程序来处理。还必须为网络应用程序指定一个端口号,计算机上不能有2个使用同一端口的程序运行。

当数据到达第一个网络程序所在的计算机后,驱动程序根据数据包中的端口号,就知道将这个数据包交给这个网络程序。

 

Udptcp

Tcp是面向连接的通信协议,提供2台计算机之间的可靠无差错的数据传输。应用程序利用tcp进行通信时,源和目的直接会建立一个虚拟链接。

 

Udp是无连接通信协议,udp不保证可靠数据的传输,但能够向若干个目标发送数据,接收发自若干个源的数据。

 

数据包的基本格式:

协议类型

ip

目的ip

源端口

目的端口

帧序号

帧数据

其中协议类型用于区分tcpudp

 

Socket

Socket是网络驱动层提供给应用程序的接口和一种机制。

可以认为socket是应用程序创建的一个港口码头,应用程序只要把装着货物的集装箱(要发送的数据)放在码头上,就算完成了货物的运送,剩下的工作就由货运公司(驱动程序)去处理了。

对接收方来说,应用程序也要创建一个码头,然后就一直等待该码头的货物到达,最后从码头上取走货物(数据)。

 

Socket在应用程序中创建,通过一个绑定机制与驱动程序建立关系,告诉自己所对应的ipport。此后,应用程序送给socket的数据,由socket交给驱动程序向网络上发送。计算机从网络收到与该socket绑定的ipport相关数据后,由驱动程序交给socket,应用程序便可以从该sokcet中取得接收到的数据。

 

Java分别为udptcp2种通信协议提供了相应的编程类,存放在java.net包中,与udp对应的是DatagramSocket,与tcp对应的是ServerSocket(用于服务器)和Socket(用于客户端)。

 

Jav编写udp网络程序

 

Java.net.DategramSocket 的构造函数主要有以下几种:

Public DatagramSocket() throws SocketException

Public DatagramSocket(int port) throws SocketException

Public DatagramSocket(int port,InetAddress laddr) throws SocketException

编写发送程序时,我们可以用第一个构造函数(创建DatagramSocket对象时,不指定端口号,系统就会为我们分配一个端口号)。

注意:第三个构造函数创建DatagramSocket对象,除了指定自己想要的端口号外,还可以指定相关的ip地址,这个情况适合计算机上有多个网卡和多个ip的情况。其实对于只有一块网卡的情况,如果在这里指定了ip地址,反而会给程序带来很大的不方便,因为这个网络程序只能在具有这个ip的计算机上运行,而不能在其他计算机上面运行。

 

编写接收程序时,我们必须自己指定一个端口号,而不让系统随即分配,可以使用第二个构造函数。

 

如果程序不在使用某个sokcet,应该调用DatagramSocket.close()方法,关闭这个socket,通知驱动程序释放为这个socket所保留的资源,系统就可以将这个socket所占用的端口号重新分配给其他程序使用。

 

在发送数据时,我们用Datagram.send()方法,

public void send(DatagramPacket p) throws IOException

 

在接收数据时,我们用Datagram.receice()方法,

public void receive(DatagramPacket p) throws IOException

 

2个方法都需要传递一个DatagramPacket类的实例对象,如果把DatagramSocket比作创建的码头,那么DatagramPacket就是我们发送和接收数据的集装箱。

 

DatagramPacket类构造函数主要有:

public DatagramPacket(byte[] buf,int length)

public DatagramPacket(byte[] buf, int length, InetAddress address, int port)

 

在接收数据时,我们应该用第一个构造函数来创建接收数据的DatagramPacket对象。

在发送数据时,我们必须指定接收方socket的地址和端口号,所以我们应该用第二个构造函数来创建发送数据的DatagramPacket对象。

 

最简单的udp程序:接收应用程序的端口号为3000。发送程序的端口号由系统分配。

import java.io.IOException;

import java.net.*;

public class UdpSend

{

               public static void main(String [] args)

               {

                               DatagramSocket ds = null;

                               try {         ds = new DatagramSocket();

                               } catch (SocketException e) {

                                              e.printStackTrace();

                               }

                               String str="hello world";

                               DatagramPacket dp = null;

                               try {dp = new DatagramPacket(str.getBytes(),str.length(),InetAddress.getByName("192.168.1.101"),3000);

                               } catch (UnknownHostException e1) {

                               e1.printStackTrace();

                               }

                               try {ds.send(dp);

                               } catch (IOException e2) {

                                              e2.printStackTrace();

                               }

                               ds.close();

                               }

}

 

import java.io.IOException;

import java.net.*;

public class UdpRecv

{

               public static void main(String [] args )

               {

                                              DatagramSocket ds=null;

                                              try{ds=new DatagramSocket(3000);}

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

                                              byte[] buf=new byte[1024];

                                             

                                              DatagramPacket dp=null;

                                              dp=new DatagramPacket(buf,1024);

                                              try {         ds.receive(dp);

                                              } catch (IOException e1) {

                                                             // TODO Auto-generated catch block

                                                             e1.printStackTrace();

                                              }

                                             String str=new String(dp.getData(),0,dp.getLength()) + " from " + dp.getAddress().getHostAddress() + ":" +dp.getPort();

//public String(byte[] byte)是将数组中的所有元素都转换成字符串,包括哪些没有填充的单元

// public String(byte[] bytes,int offset,int length)是将字节数组中从offset开始,往后一共length

//个单元的内容转换成字符串

                                              System.out.println(str);

                                              ds.close();

               }             

}

 

Java编写tcp网络程序:

利用tcp协议进行通信的2个应用程序,是有主次之分的。一个称为服务器程序,另外一个称为客户机程序。2者的能够和编写方法大不一样。

服务器和客户端交互过程:

1、服务器程序创建一个ServerSocket,然后调用accept方法等待客户来链接。

2、客户端程序创建一个Socket并请求与服务器建立连接。

3、服务器接收客户的连接请求,并创建一个新的sokcet与该客户建立专线连接。

4、刚才建立了连接的2socket在一个单独的线程(由服务器程序创建)上对话。

5、服务器开始等待新的连接请求。

 

ServerScoket

构造方法:

public ServerSocket() throws IOException

public ServerSocket(int port) throws IOException

public ServerSocket(int port,int backlog) throws IOException

public ServerSocket(int port,int backlog,InetAddress bindAddr) throws IOException

 

第一个:没有与任何端口号绑定,不能直接使用,还要调用bind方法才能完成构造函数所完成的工作。

第二个:创建serverSocket对象,可以将这个serverSocket绑定到一个指定的端口上,作为服务器程序,端口号必须事先指定,其他客户才能根据这个号码进行连接。所以将端口号指定为0的情况并不常见。

第三个:创建serverSocket对象,就是在第二个构造函数的基础上,我们根据backlog参数指定,在服务器忙时,可以与之保持连接请求的等待客户数量,对于第二个构造函数,没有指定这个参数,则使用默认的数量,大小为50

第四个:创建serverSocket对象,除了指定第三个构造函数中的参数外,还可以指定相关的ip地址,这种情况适用于计算机上有多个网卡和多个ip的情况。对于一般情况只有一块网卡的情况,就不用指定ip了。

 

第二个构造方法比较适合创建我们的serversocket对象。

 

Socket

客户端于服务器建立连接,首先必须创建一个sokcet对象,它的构造方法:

public Socket()

public Socket(String host,int port)throws UnknownHostException,IOException

public Socket(InetAddress address,int port) throws IOException

public Socket(String host,int port,InetAddress localAddr,int localPort) throws IOException

public Socket(InetAddress address,int port,InetAddress localAddr,     int localPort) throws IOException

 

第一个:能够创建sokcet对象,不与任何服务器建立连接,不能直接使用,还要调用connect方法才能完成构造函数所完成的工作。

第二个:创建socket对象后,会根据参数去连接在特定地址和端口上运行的服务器程序,接收字符串格式的地址。

第三个:创建socket对象后,会根据参数去连接在特定地址和端口上运行的服务器程序,接收InetAddress对象所包装的地址。

第四个和第五个:在第二个和第三个构造函数的基础上,还指定了本地sokcet所绑定的ip地址和端口号,由于客户端的端口号的选择不重要,所以一般情况下,我们不会使用这2个构造函数。

 

我们选择第二个构造函数来创建客户端的socket对象并与服务器建立连接。

 

服务器端程序调用serversokcet.accept方法等待客户的连接请求,一旦accept接收了客户连接请求,该方法将返回一个与该客户建立专线连接的sokcet对象,不用程序去创建这个socket对象。当客户端和服务器端的2sokcet建立了专线连接后,连接的一端能向另外一端连续写入字节,也能从另外一端连续读入字节,就是建立了专线连接的2sokcet是以io流的方式进行数据交换的。Java提供了sokcet.getInputStream方法返回socket的输入流对象,socket..getOutputstrram方法返回sokcet的输出流对象。只要连接的一端向该输出流对象写入了数据,连接的另一端就能从输入流对象这读取到这些数据。

 

简单的服务器程序:

import java.net.*;

import java.io.*;

public class TcpServer {

               public static void main(String[] args) {

                               try{

                                              ServerSocket ss=new ServerSocket(8001);

                                              Socket s=ss.accept();

                                              InputStream ips=s.getInputStream();

                                              OutputStream ops=s.getOutputStream();

                                              ops.write("welcome to www!".getBytes());//通过输出流首先向客户端发送一串字符

                                              byte [] buf=new byte[1024];

                                              int len=ips.read(buf);//通过输入流读取客户端发来的信息,并保存到一个字节数组中

                                              System.out.println(new String(buf,0,len));

                                              ips.close();

                                              ops.close();

                                              s.close();

                                              ss.close();

                               }

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

               }

}

上面的代码如果在telnet中输入一个字母,就会发送到服务器端,马上就退出了。为了实现客户端输入一行字母,代码修改如下:

 

import java.net.*;

import java.io.*;

public class TcpServer {

               public static void main(String[] args) {

                               try{

                                              ServerSocket ss=new ServerSocket(8001);

                                              Socket s=ss.accept();

                                              InputStream ips=s.getInputStream();

                                              OutputStream ops=s.getOutputStream();

                                              ops.write("welcome to www!".getBytes());//通过输出流首先向客户端发送一串字符

                                              BufferedReader br=new BufferedReader(new InputStreamReader(ips));;

                                              //byte [] buf=new byte[1024];

                                              //int len=ips.read(buf);//通过输入流读取客户端发来的信息,并保存到一个字节数组中

                                              //System.out.println(new String(buf,0,len));

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

                                              //ips.close();

                                              br.close();//关闭包装类,会自动关闭包装类中所包装的底层类。所以不用调用ips.close()

                                              ops.close();

                                              s.close();

                                              ss.close();

                               }

                               catch(Exception e)

                               {e.printStackTrace();}

               }

}

 

完善的tcp服务器程序模型:

import java.io.*;

import java.net.*;

 

public class Servicer implements Runnable{

               Socket s;

               public Servicer(Socket s)

               {

                               this.s=s;

               }

               public void run()

               {

                               try{

                                              InputStream ips=s.getInputStream();

                                              OutputStream ops=s.getOutputStream();

                                              BufferedReader br=new BufferedReader(new InputStreamReader(ips));

                                              DataOutputStream dos=new DataOutputStream(ops);

                                              while(true)

                                              {

                                                             String str=br.readLine();

                                                             if(str.equalsIgnoreCase("quit"))

                                                                            break;

                                                            

                                                             String strEcho=(new StringBuffer(str)).toString();

//String strEcho=(new StringBuffer(str).reverse()).toString();

                                                             dos.writeBytes(str + "--->" + strEcho + System.getProperty("line.separator"));

                                              }

                                              br.close();

                                              dos.close();

                                              s.close();

                               }

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

               }

}

 

class TcpServer

{

               public static void main(String [] args)

               {

                               try{

                                              ServerSocket ss=new ServerSocket(8001);

                                              while(true)

                                              {

                                                             Socket s=ss.accept();

                                                             new Thread(new Servicer(s)).start();

                                              }

                               }

                               catch(Exception e1){e1.printStackTrace();}

               }

}

 

import java.net.*;

import java.io.*;

public class TcpClient {

               public static void main(String[] args) {

                               try{

                                              if(args.length<2)

                                              {

                                                             System.out.println("Usage:java Tcpclient serverIP serverPort");

                                                             return;

                                              }

                                             

                                              Socket s=new Socket(InetAddress.getByName(args[0]),Integer.parseInt(args[1]));

                                              InputStream ips=s.getInputStream();

                                              OutputStream ops=s.getOutputStream();

                                              BufferedReader brkey=new BufferedReader(new InputStreamReader(System.in));

                                              DataOutputStream dos=new DataOutputStream(ops);

                                              BufferedReader brnet=new BufferedReader(new InputStreamReader(ips));

                                             

                                              while(true)

                                              {

                                                             String strW=brkey.readLine();

                                                             dos.writeBytes(strW + System.getProperty("line.separator"));

                                                             if (strW.equalsIgnoreCase("quit"))

                                                                            break;

                                                             else

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

                                              }

                                              dos.close();

                                              brnet.close();

                                              brkey.close();

                                              s.close();

                               }

                               catch(Exception e){e.printStackTrace();                                  

                               }

                              

               }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值