网络编程学习笔记2(TCP/UDP协议)

1、Socket编程。两个JAVA应用程序可通过一个双向的网络通信连接实现数据交换,这个双向链路的一段称为一个Socket。

2、跟网络相关的一些类都位于java.net包中。

3、Socket通常用来实现client-server连接。

4、java.net包中定义的两个类,分别用来实现双向连接的client和server端。

5、建立连接是所需的寻址信息为远程计算机的IP地址和端口号(Port number).

6、端口号是什么:我QQ和邮箱都可以发送消息,为什么我QQ上发送的东西跑到了你的QQ上,却跑不到你的邮箱里呢?这就说明在我的机器上其实还有一种东西来区分中这些应用程序。在网络技术中,端口(Port)包括逻辑端口和物理端口两种类型。物理端口指的是物理存在的端口,如ADSL Modem、集线器、交换机、路由器上用 于连接其他网络设备的接口,如RJ-45端口、SC端口等等。逻辑端口是指逻辑意义上用于区分服务的端口,如TCP/IP协议中的服务端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等。由于物理端口和逻辑端口数量较多,为了对端口进行区分,将每个端口进行了编号,这就是端口号。(摘选自百度百科。)

7、   端口号你占了一个就是你的,系统可能会随时征用了1024以下的端口号,所以不要用1024以下的端口。端口号又分为TCP端口、UDP端口,各有65536个端口,端口号占两个字节,每一个都是65536个端口。一般一public int getLocalPort()个应用程序可以有多个端口。有一些端口已经被占了。

一般系统有自己的算法,你在一台机器上启动客户端,每次客户端的端口号就有极大可能是不相同的。

8、Socket类

此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器之间的通信端点。

public Socket(String host , int port) throws UnknownHostException, IOException{}这个构造方法参数传入IP地址和端口号,创建一个流套接字并将其连接到指定主机上的指定端口号。该构造方法声明了两种异常。


public InputStream getInputStream() throws IOException该方法用来返回一个套接字的输入流,

public OutputStream getOutputStream()throws IOException该方法用来返回一个套接子的输出流。

public InetAddress getLocalAddress()方法获取套接字绑定的本地地址。

public int getPort() 返回此套接字连接到的远程端口。对方端口号。

public int getLocalPort() 返回此套接字绑定到的本地端口


9、ServerSocket类erverSocket
public ServerSocket(int port) throws IOException  构造方法。 创建绑定到特定端口的服务器套接字。端口 0 在所有空闲端口上创建套接字。

这个是等待客户端的连接。

ServerSocket类有一个accept()方法,这个方法是一个阻塞式的方法,是用来接受客户端的请求,返回一个Socket类型,用来和客户端进行连接。如果有多个客户端请求连接,连接一个就调用一次这个accept()方法,返回一个Socket对象。


public Socket accept()  throws IOException声明了一个IOException。

public InetAddress getInetAddress() 返回此服务器套接字的本地地址。

public int getLocalPort()返回此套接字在其上侦听的端口。

public SocketAddress getLocalSocketAddress()返回此套接字绑定的端点的地址,如果尚未绑定则返回 null


该方法可能抛出以下的异常

IOException - 如果等待连接时发生 I/O 错误。
SecurityException - 如果安全管理器存在并且其 checkListen 方法不允许进行该操作。 (父类RuntimeException,可以不声明异常,可能会抛出该异常
SocketTimeoutException - 如果以前使用 setSoTimeout 设置了超时并且已到达超时值。 (其间接父类是IOException,不属于RuntimeException
IllegalBlockingModeException - 如果此套接字具有相关联的通道、通道处于非阻塞模式并且不存在准备接受的连接(间接父类RuntimeException,可以不声明异常,可能会抛出该异常


10、一旦我们连接成功之后,我们通过流来说话。(一下代码中存在很大的问题,是我自己实验的,不作为标准的聊天小程序。)

import java.io.*;
import java.net.*;
public class TestTalkStudent{
public static void main(String[] args){
OutputStream out=null;
InputStream in=null;
DataInputStream ins=null;
DataOutputStream outs=null;
Socket socket=null;
BufferedReader ss=null;

try{
socket=new Socket("10.106.35.72",7777);
in=socket.getInputStream();
out=socket.getOutputStream();
ins=new DataInputStream(in);
outs=new DataOutputStream(out);
String s1=null;
String s2=null;
while(true){
//System.out.print("You Say: ");
ss=new BufferedReader(new InputStreamReader(System.in));
s2=ss.readLine();
outs.writeUTF("Student Say: "+s2);
s1=ins.readUTF();
System.out.println(s1);
if(s1.equalsIgnoreCase("exit")&&s2.equalsIgnoreCase("exit")){
break;
}

}

}catch(IOException e){
e.printStackTrace();
}
try{
out.close();
in.close();
outs.close();
ins.close();
socket.close();
ss.close();
}catch(IOException e){
e.printStackTrace();
}
}
}




import java.io.*;
import java.net.*;
public class TestTalkTeacher{
public static void main(String[] args){
DataInputStream ins=null;
DataOutputStream outs=null;
ServerSocket server=null;
Socket socket=null;
BufferedReader ss=null;
try{
server=new ServerSocket(7777);
socket=server.accept();
ins=new DataInputStream(socket.getInputStream());
outs=new DataOutputStream(socket.getOutputStream());
String s1=null;
String s2=null;
while(true){
s1=ins.readUTF();



System.out.println(s1);
ss=new BufferedReader(new InputStreamReader(System.in));
s2=ss.readLine();
System.out.println("You Say: ");
outs.writeUTF("Teacher Say: "+s2);
outs.flush();
if(s1.equalsIgnoreCase("exit")&&s2.equalsIgnoreCase("exit")){
break;
}
}


}catch(IOException e){
e.printStackTrace();
}
try{
outs.close();
ins.close();
server.close();
socket.close();
ss.close();
}catch(IOException e){
e.printStackTrace();
}

}
}

终于到了UDP

UDP中有个很重要的类是DatagramPacket类,此类表示数据报包,我们用这个类来构造一个一个数据包。

UDP中是将一个一个数据打成数据包发送出去。

DatagramPacket(byte[] buf, int length)
          构造 DatagramPacket,用来接收长度为length 的数据包。
DatagramPacket(byte[] buf, int length,InetAddress address, int port)
          构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int offset, int length)
          构造 DatagramPacket,用来接收长度为length 的包,在缓冲区中指定了偏移量。
DatagramPacket(byte[] buf, int offset, int length,InetAddress address, int port)
          构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int offset, int length,SocketAddress address)
          构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。
DatagramPacket(byte[] buf, int length,SocketAddress address)
          构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。

DatagramPacket类的构造方法。我们是用一个数组来承接这个数据。不管是将其发出还是将其接收。

该类有一个方法叫做getLength()

public int getLength()返回将要发送或接收到的数据的长度。

该方法返回的是数据的长度,而不是整体的容量长度

其中有必要讲一下InetAddress这个类。此类表示互联网协议 (IP) 地址。

它有两个子类,分别是  Inet4Address(IPv4地址),Inet6Address(IPv6地址)(没有构造方法,通过里面的get方法传入字符串或是数组,返回InetAddress类型,有必要讲的是getAddress()方法,将IP地址返回为一个byte类型的数组,我们知道byte类型是一个字节,所以我们可以直接获取数组的长度,判断这个长度是4还是16,是4的话就是IPv4,是16的话就是IPv6)。

还有必要讲的是SocketAddersss类。

public abstract class SocketAddress  extends  Object  implementsSerializable

该类是一个抽象类,其子类为InetSocketAddress。  public class InetSocketAddressextends SocketAddress

InetSocketAddress(InetAddress addr, int port)
          根据 IP 地址和端口号创建套接字地址。
InetSocketAddress(int port)
          创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。
InetSocketAddress(String hostname, int port)
          根据主机名和端口号创建套接字地址。
子类还有一个获取IP和端口号的方法,这里不做一 一 讲解。自己可以查阅API文档。


接下来就是还有一个重要的类,想想我们已经创建好发送数据的数据包了,那我们是不是要在客户端和服务器端都有分别有一个插座将两段连接起来呢。

这个类就是DatagramSocket


 DatagramSocket()
          构造数据报套接字并将其绑定到本地主机上任何可用的端口。
protectedDatagramSocket(DatagramSocketImpl impl)
          创建带有指定 DatagramSocketImpl 的未绑定数据报套接字。(注意这里是DatagramSocket,而不是DatagramPacket,对于数据包我们有个sent方法直接发送出去就行了。
 DatagramSocket(int port)
          创建数据报套接字并将其绑定到本地主机上的指定端口。(一般是服务器端
 DatagramSocket(int port,InetAddress laddr)
          创建数据报套接字,将其绑定到指定的本地地址。(一般是服务器端,这样创建套接字。
 DatagramSocket(SocketAddress bindaddr)
          创建数据报套接字,将其绑定到指定的本地套接字地址。(一般是服务器端

该类有一个方法   public void receive(   DatagramPacket   p   ) throws IOException 从此套接字接收数据报包

当此方法返回时,DatagramPacket 的缓冲区填充了接收的数据。数据报包也包含发送方的 IP 地址和发送方机器上的端口号。

该类还有一个方法,public void send(DatagramPacket p) throws IOException 从此套接字发送数据报包。DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。

import java.net.*;
import java.io.*;
public class TestUdpServer{
	public static void main(String[] args){
		byte[] byts=new byte[1024];
		DatagramPacket packet=new DatagramPacket(byts,0,byts.length);//将即将要接收到的数据用字节数组byts来承接,那个长度可以不是字节数组的长度。
		DatagramSocket  socket=null;
		try{
			socket=new DatagramSocket(8888);//指定服务器端口号,等待客户端连接。
		}catch(SocketException e){
			e.printStackTrace();
		}
		try{
			socket.receive(packet);//接收数据包,上面有介绍这个方法。
		}catch(IOException e){
			e.printStackTrace();
		}
		System.out.println(new String(byts,0,packet.getLength()));
		socket.close();
	}
}
import java.net.*;
import java.io.*;
public class TestUdpClient{
	public static void main(String[] args){
		byte[] byts=new String("hello").getBytes();
		DatagramPacket pp=new DatagramPacket(byts,0,byts.length,new InetSocketAddress("10.106.35.72",8888));//直接在数据包中指定对方IP地址和端口号
		DatagramSocket socket=null;
		try{
			socket=new DatagramSocket();//数据包中制定了IP和端口号,这里可以不用指定。
		}catch(SocketException e){
			e.printStackTrace();
		}
		try{
			socket.send(pp);//发送数据包。
		}catch(IOException e){
			e.printStackTrace();
		}
		socket.close();
	}
}

import java.net.*;
import java.io.*;
public class TestLongClient{
	public static void main(String[] args){
		long n=1245789L;
		ByteArrayOutputStream byteout=new ByteArrayOutputStream();
		
		DataOutputStream out=new DataOutputStream(byteout);
		try{
			out.writeLong(n);
		}catch(IOException e){
			e.printStackTrace();
		}
		byte[] bb=byteout.toByteArray();
		
		DatagramPacket packet=new DatagramPacket(bb,bb.length,new InetSocketAddress("10.106.35.72",8888));
		/*InetAddress  address=null;
		try{
			address=InetAddress.getByName("10.106.35.72");
		}catch(Exception e){
			e.printStackTrace();
		}*/
		DatagramSocket socket=null;
		try{
			socket=new DatagramSocket();
		}catch(SocketException e){
			e.printStackTrace();
		}
		
		try{
			socket.send(packet);
			byteout.close();
			out.close();
		}catch(IOException e){
			e.printStackTrace();
		}
		
		
	}
}

import java.net.*;
import java.io.*;
public class TestLongServer{
	public static void main(String[] args){
		
		byte[] buf=new byte[100];
		DatagramPacket packet=new DatagramPacket(buf,buf.length);
		DatagramSocket socket=null;
		try{
			socket=new DatagramSocket(8888);
		}catch(SocketException e){
			e.printStackTrace();
		}
		try{
			socket.receive(packet);
		}catch(IOException e){
			e.printStackTrace();
		}
		ByteArrayInputStream bytein=new ByteArrayInputStream(buf);
		DataInputStream in=new DataInputStream(bytein);
		try{
			long l=in.readLong();
			System.out.println(l);
			bytein.close();
			in.close();
		}catch(IOException e){
			e.printStackTrace();
		}
	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值