java网络编程(TCP与UDP)

TCP客户端;

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

public class TCPClient
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("127.0.0.1", 6666);   //8行
					//第一个参数是要连接到的主机IP,即表示要连接到那台机器上,127.0.0.1表示链接到本机, 第二个参数表示要连接到哪个网络程序上
					//new Socket("127.0.0.1", 6666) 一旦构造对象成功,就意味着这时已经产生了一个试图和IP为"127.0.0.1" 端口为6666的网络程序进行连接的请求
					//如果这时IP为"127.0.0.1" 的机器上正好有一个网络程序在监听6666端口,这时连接就会建立成功
					//所谓连接成功是指这两个网络程序建立了一个通信管道,双方都可以通过这个管道写数据和读数据,并且一方写入的数据实际就是另一方要读取的数据,一方要读取的数据实际就是另一放要写入的数据, 即这个管道实际是双向的,任何一方都可以通过getInputStream() 和 getOutputStream()获取输入流和输出流两个流,并且一方的输入流实际就是另一方的输出流,这是同一个流,一方的输出流实际就是另一方的输入流,这也是同一个流 即一个通信管道两个流,双方各自都可以得到两个流,这两个流分别是输入流和输出流
					//记住:一旦new出了Socket对象,该对象就会自动向服务器端发送连接请求,如果连接不成功则程序立即终止
					//因此我们在TCP编程的客户端是找不到请求连接的代码,但是在服务器端却存在监听客户端连接请求的代码, 代码类似于:ss.accept()
		
		OutputStream os = s.getOutputStream(); //16行  一旦连接成功,相当于建立了一根管道,这根管道在客户端相当于输出流管道,在服务器端相当于输入流管道! 
						//程序如果能执行到16行说明已经连接成功,因为8行执行完后就会自动立即发送一个连接请求,如果服务器端没有打开,或者服务器端虽然已经打开但是却没有监听客户端的连接请求,则程序会立即终止,是不会执行到16行的, 如果执行到了16行那说明连接成功了
		
		DataOutputStream dos = new DataOutputStream(os);
		dos.writeUTF("同志们好");
		dos.flush();
		dos.close();
		s.close();		
	}
}


TCP服务端:

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

public class TCPServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(6666);//8行  6666是端口号,表示该服务器程序在监听6666端口是否有客户端程序的连接
					//new出的ServerSocket对象ss并不会自动监听客户端有没有向6666端口发送请求,要想监听6666端口是否有客户端的请求,则必须的调用ss对象的accept方法
					//如果本程序只有8行这一行的代码的话,本程序运行时将无任何输出结果并会立即终止								
		
		while (true)
		{
			Socket s = ss.accept();  //accept()功能:等待客户端的连接,没有连接,则继续监听,程序停滞不前,如果接收到客户端的一个连接,则自动将该连接封装为一个Socket对象,程序将不再阻塞,而是继续放下执行  
						//这里的s实际是链接到客户端的s,服务器端的s.getInputStream() 和客户端的s.getOutputStream()实际是同一根管道
						//accept()是阻塞式方法,如果接收不到客户端的连接,则程序将停止不前
			System.out.println("一个连接已经建立!!!");
			DataInputStream dis = new DataInputStream(s.getInputStream()); //通过Socket对象可以获得InputStream和OutputStream两个管道
			System.out.println(dis.readUTF());  //readUTF()方法也是阻塞式方法,如果接收不到客户端数据,则程序将停止不前
			dis.close();  //DataInputStream 和 InputStream 流中都没有flush方法  DataOutputStream 和 OutputStream 流中都有flush方法
			s.close();
		}	
	}
}


UDP客户端:

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

public class TestUDPClient
{
	public static void main(String args[]) throws Exception
	{
		//定义码头ds
		DatagramSocket ds = new DatagramSocket();
		
		
		//13行到23行完成的功能是: 定义可以发送数据的集装箱dp,dp中保存着n的二进制代码
		long n = 10000L; //13行
		ByteArrayOutputStream baos = new ByteArrayOutputStream();  //注意ByteArrayOutputStream的所有构造函数都没有byte[] buf这样的形参,即定义ByteArrayOutputStream流对象时是不能指定byte数组的,因为这个连接到的byte数组是由ByteArrayOutputStream自动生成的  9行  API:"public ByteArrayOutputStream(): 创建一个新的 byte 数组输出流。缓冲区的容量最初是 32 字节,如有必要可增加其大小。 "
									//9行代码一旦执行完毕,意味着两点: 1、在内存中生成了一个大小为32个字节的byte数组   2、有一根叫做baos的管道已链接到了该byte数组中,并且可以通过这个管道向该数组中写入数据
									//虽然此时可以通过baos向baos所连接到的在内存中分配好的byte数组中写入数据,但是ByteArrayOutputStream流并没有提供可以直接把long类型数据直接写入ByteArrayOutputStream流所连接到的byte数组中的方法, 简单说我们没法通过baos向baos所连接到的byte数组中写入long类型的数据, 查API文档可以发现: ByteArrayOutputStream流中并没有类似writeLong()这样的方法,但是DataOutputStream流中却有writeLong() writeFloat()等方法
		DataOutputStream dos = new DataOutputStream(baos);
		dos.writeLong(n);  //把n变量所代表的10000L写入dos所依附的baos管道所连接到的内存中的大小为32字节的byte数组中
		
		byte[] buf = baos.toByteArray();  //DataOutputStream 流中并没有toByteArray()方法,但是ByteArrayOutputStream 流中却有toByteArray()方法, 所以不可以把baos 改为dos,否则编译时会出错! ByteArrayOutputStream流中toByteArray()方法的含义,摘自API“创建一个新分配的 byte 数组。其大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中”
		DatagramPacket dp = new DatagramPacket(buf, buf.length, 
											   new InetSocketAddress("127.0.0.1", 5678)
											   );  //23行
		
		//在码头上把集装箱中的数据发送给对方
		ds.send(dp);
		
		//关闭码头
		ds.close();		
	}
}


UDP服务端:

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

public class TestUDPServer
{
	public static void main(String args[]) throws Exception
	{
		//定义码头
		DatagramSocket ds = new DatagramSocket(5678);  //5678表示该码头占用的是5678这个编号,因为一台计算机可以有多个码头接收多个数据,这些码头用不同的编号来表示,这些编号的专业术语就是端口号
		
		
		//定义可以用来接受数据的集装箱
		byte buf[] = new byte[1024];
		DatagramPacket dp = new DatagramPacket(buf, buf.length);
		
		try
		{
			while(true)
			{
				//在码头上用集装箱接受对方发送过来的数据
				ds.receive(dp); //注意:本语句执行完毕就意味着,dp数据包中就已经含有了从客户端接收过来的数据
				
				//从集装箱中取出对方发送过来的数据
				ByteArrayInputStream bais = new ByteArrayInputStream(dp.getData()); //1、 ByteArrayInputStream的内核必须是个字节数组,并且是从该字节数组中读取数据  2、dp.getData()表示把dp集装箱中的数据转化为一个字节数组并返回该字节数组  
				DataInputStream dis = new DataInputStream(bais);
				System.out.println(dis.readLong()); 
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
			ds.close();  //关闭码头
		}
		
	}
}
/*
	在JDK 1.6中的运行结果是:
----------------------------------
10000
数据源自: 127.0.0.1 : 1464
10000
数据源自: 127.0.0.1 : 1471
10000
数据源自: 127.0.0.1 : 1474
----------------------------------
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值