网络编程UDP和TCP的简单使用



1.网络编程概述

计算机网络

	* 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,
	* 在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。

网络编程

	* 就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。




2.网络编程三要素,IP,端口,协议.

IP地址

*互联网协议地址(英语:Internet Protocol Address,又译为网际协议地址),
*缩写为IP地址(IP Address)。
*IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,
*以此来屏蔽物理地址的差异。
*
*常见的IP地址分为IPv4与IPv6两大类。
*
*ipconfig /all 查看Windows的IP地址
* 本地回路地址:127.0.0.1 
*所有人广播:255.255.255.255

端口号port

* 每个程序在设备上的唯一标识
* 每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序。
* 端口号范围从0-65535
* 编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。
* 常用端口
	* mysql: 3306
	* oracle: 1521
	* web: 80
	* tomcat: 8080
	* QQ: 4000

协议

* 为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
* UDP
	* 面向无连接,数据不安全,速度快。不区分客户端与服务端。
* TCP
  * 面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。
	* 三次握手: 客户端先向服务端发起请求, 服务端响应请求, 传输数据



3.Socket通信原理

Socket套接字概述:

      * 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
	* 通信的两端都有Socket。
	* 网络通信其实就是Socket间的通信。
	* 数据在两个Socket间通过IO流传输。
	* Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port。

Socket

java.lang.Object
——java.net.Socket
直接已知子类:SSLSocket 
public class Socket extends Object
此类实现客户端(或服务端)套接字(也可以就叫“套接字”)。
套接字是两台机器间通信的端点。 
套接字的实际工作由 Socket类的实例执行。

public Socket(InetAddress address, int port) throws IOException
	创建一个流套接字并将其连接到指定 IP 地址的指定端口号。

public InputStream getInputStream() throws IOException
	 返回此套接字的输入流。


 public OutputStream getOutputStream() throws IOException
	返回此套接字的输出流。 
 
public void close() throws IOException
	关闭此套接字。
	 套接字被关闭后,便不可在以后的网络连接中使用(即无法重新连接或重新绑定)。
	需要创建新的套接字。
	关闭此套接字也将会关闭该套接字的 InputStream 和 OutputStream。 
	如果此套接字有一个与之关联的通道,则关闭该通道。 


4.UDP传输


DatagramSocket

java.lang.Object
———java.net.DatagramSocket
直接已知子类: MulticastSocket 
public class DatagramSocket extends Object
此类表示用来发送和接收数据报包的(数据报)套接字。 
数据报套接字是包投递服务的发送或接收点。
每个在数据报套接字上发送或接收的包都是单独编址和路由的。
从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。
 
public DatagramSocket() throws SocketException
	构造数据报套接字并将其绑定到本地主机上任何可用的端口。

public DatagramSocket(int port) throws SocketException
	创建数据报套接字并将其绑定到本地主机上的指定端口。
               
public void send(DatagramPacket p) throws IOException
	从此套接字发送数据报包。
	DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。 

public void receive(DatagramPacket p) throws IOException
	从此套接字接收数据报包。
	当此方法返回时,DatagramPacket 的缓冲区填充了接收的数据。
	数据报包也包含发送方的 IP 地址和发送方机器上的端口号。 
	此方法在接收到数据报前一直阻塞。
	数据报包对象的 length 字段包含所接收信息的长度。
	如果信息比包的长度长,该信息将被截短。 

public void close()
	关闭此数据报套接字。 
	如果此套接字有一个与之关联的通道,则关闭该通道。 



DatagramPacket

java.lang.Object
——java.net.DatagramPacket
public final class DatagramPacketextends Object
此类表示数据报包。 
数据报包用来实现无连接包投递服务。
每条报文仅根据该包中包含的信息从一台机器路由到另一台机器
从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。
不对包投递做出保证。 

public DatagramPacket(byte[] buf, int length, InetAddress address, int port)
	构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
	length 参数必须小于等于 buf.length。 
	参数:
	buf - 包数据。
	length - 包长度。
	address - 目的地址。
	port - 目的端口号。

public DatagramPacket(byte[] buf, int length)
	构造 DatagramPacket,用来接收长度为 length 的数据包。 
	length 参数必须小于等于 buf.length。 
	参数:
	buf - 保存传入数据报的缓冲区。
	len - 要读取的字节数。

public byte[] getData()
	返回数据缓冲区。
	接收到的或将要发送的数据从缓冲区中的偏移量 offset 处开始,持续 length 长度。 

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

public InetAddress getAddress()
	返回某台机器的 IP 地址,

public int getPort()
	返回某台远程主机的端口号,



InetAddress

java.lang.Object
—java.net.InetAddress
所有已实现的接口:Serializable 
直接已知子类: Inet4Address, Inet6Address 
public class InetAddress extends Object implements Serializable
此类表示互联网协议 (IP) 地址。 
IP 地址是 IP 使用的 32 位或 128 位无符号数字,它是一种低级协议,UDP 和 TCP 协议都是在它的基础上构建的。

public static InetAddress getByName(String host) throws UnknownHostException
	在给定主机名的情况下确定主机的 IP 地址。 
	主机名可以是机器名(如 "java.sun.com"),也可以是其 IP 地址的文本表示形式。
	如果提供字面值 IP 地址,则仅检查地址格式的有效性



UDP传输案例


发送

相关解释都在代码里


* 创建DatagramSocket, 随机端口号
* 创建DatagramPacket, 指定数据, 长度, 地址, 端口
* 使用DatagramSocket发送DatagramPacket
* 关闭DatagramSocket


1.创建Socket相当于创建码头
2.创建Packet相当于集装箱
3.通过码头发货,将数据发过去
4.关闭码头


import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class c_send {

	public static void main(String[] args) throws Exception {
		String str = "what are you doing?";
		DatagramSocket socket = new DatagramSocket();//1.创建Socket相当于创建码头
		DatagramPacket packet = new DatagramPacket(	//2.创建Packet相当于集装箱(货)
				str.getBytes(),
				str.getBytes().length, 
				InetAddress.getByName("127.0.0.1"), 6666);
		socket.send(packet);		//3.通过码头发货,将数据发出去
		socket.close();				//4.关闭码头,底层是io流需要关闭
		
		
		System.out.println(InetAddress.getByName("127.0.0.7"));///127.0.0.7
		System.out.println(InetAddress.getAllByName("127.0.0.7"));
		//[Ljava.net.InetAddress;@10dea4e
	}

}

接收


	* 创建DatagramSocket, 指定端口号
	* 创建DatagramPacket, 指定数组, 长度
	* 使用DatagramSocket接收DatagramPacket
	* 关闭DatagramSocket
	* 从DatagramPacket中获取数据

1.创建Socket相当于创建码头,指定码头接收货物,相当于指定端口
2.创建Packet相当于创建集装箱用来接收货物.指定数组, 长度
3.通过码头接货,接收数据
4.把货物从集装箱里取出来,获取数据
5.关闭码头

import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
 * UDP传输
 * 
 * */
public class b_receive {
	
	public static void main(String[] args) throws Exception {
		
		DatagramSocket socket = new DatagramSocket(6666);	
		//1.创建Socket相当于创建码头,指定码头接收货物,相当于指定端口
		DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
		//2.创建Packet相当于创建集装箱用来接收货物.指定数组, 长度
		socket.receive(packet);	
		//3.通过码头接货,接收数据
		
		byte[] arr = packet.getData();	
		//3.把货物从集装箱里取出来,获取数据
		int len = packet.getLength();
		//4.获取有效的字节个数
		System.out.println(new String(arr,0,len));
		socket.close();
		//5.关闭码头
	}

}

先运行receive再运行send

UDP传输优化


发送


import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class d_send {

	public static void main(String[] args) throws Exception {
		
		Scanner sc = new Scanner(System.in);//创建键盘录入对象
		DatagramSocket socket = new DatagramSocket();//1.创建Socket相当于创建码头
		
		while(true){
			String line = sc.nextLine();//获取键盘录入的字符串
			if("quit".equals(line)){
				break;
			}
			DatagramPacket packet = new DatagramPacket(	//2.创建Packet相当于集装箱(货)
					line.getBytes(),
					line.getBytes().length, 
					InetAddress.getByName("127.0.0.1"), 6666);
			socket.send(packet);		//3.通过码头发货,将数据发出去
		}
		
		socket.close();				//4.关闭码头,底层是io流需要关闭
		
		
		System.out.println(InetAddress.getByName("127.0.0.7"));///127.0.0.7
		System.out.println(InetAddress.getAllByName("127.0.0.7"));
		//[Ljava.net.InetAddress;@10dea4e
	}

}


接收

import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
 * UDP传输
 * 
 * */
public class e_receive {
	
	public static void main(String[] args) throws Exception {
		
		DatagramSocket socket = new DatagramSocket(6666);	
		//1.创建Socket相当于创建码头,指定码头接收货物,相当于指定端口
		DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
		//2.创建Packet相当于创建集装箱用来接收货物.指定数组, 长度
		
		while(true){
			socket.receive(packet);	
			//3.通过码头接货,接收数据
			
			byte[] arr = packet.getData();	
			//3.把货物从集装箱里取出来,获取数据
			int len = packet.getLength();
			//4.获取有效的字节个数
			
			String ip = packet.getAddress().getHostAddress();//获取ip地址
			int port = packet.getPort();//获取端口号
			//System.out.println(new String(arr,0,len));
			System.out.println(ip + ":" + port + ":" + new String(arr,0,len));
		}
		//socket.close();一直接收不需要关闭
		//5.关闭码头
	}
}


UDP传输多线程

发送和接收在一个窗口完成


import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

/**
*发送和接收在一个窗口完成
 */
public class send_receive {

	/**
	 * @param args
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub	
		new Receive().start();
		Thread.sleep(1000);
		new Send().start();
	}

}

class Send extends Thread{
	@Override
	public void run() {
		
		try{
			Scanner sc = new Scanner(System.in);//创建键盘录入对象
			DatagramSocket socket = new DatagramSocket();//1.创建Socket相当于创建码头
			while(true){
				String line = sc.nextLine();//获取键盘录入的字符串
				if("quit".equals(line)){
					break;
				}
				DatagramPacket packet = new DatagramPacket(	//2.创建Packet相当于集装箱(货)
						line.getBytes(),
						line.getBytes().length, 
						InetAddress.getByName("127.0.0.1"), 6666);
				socket.send(packet);		//3.通过码头发货,将数据发出去
			}
			socket.close();				//4.关闭码头,底层是io流需要关闭
		}catch(Exception e){
			e.printStackTrace();
		}
	}

}

class Receive extends Thread{
	
	@Override
	//***run方法中我们不能抛异常*catch*
	public void run() {
		try{
			DatagramSocket socket = new DatagramSocket(6666);	
			//1.创建Socket相当于创建码头,指定码头接收货物,相当于指定端口
			DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
			//2.创建Packet相当于创建集装箱用来接收货物.指定数组, 长度
			while(true){
				socket.receive(packet);	
				//3.通过码头接货,接收数据
				byte[] arr = packet.getData();	
				//3.把货物从集装箱里取出来,获取数据
				int len = packet.getLength();
				//4.获取有效的字节个数
				String ip = packet.getAddress().getHostAddress();		//获取ip地址
				int port = packet.getPort();							//获取端口号
				//System.out.println(new String(arr,0,len));
				System.out.println(ip + ":" + port + ":" + new String(arr,0,len));
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
}



UDP传输GUI界面化并优化


模块设计
UDP聊天图形化界面
UDP聊天发送功能
(UDP聊天记录功能
UDP聊天清屏功能
UDP聊天震动功能
UDP聊天快捷键和代码优化
UDP聊天生成jar文件


注释都在代码里面,已经很好理解了

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class udp_gui extends Frame {

	private TextField tf;
	private Button send;
	private Button log;
	private Button clear;
	private Button shake;
	private TextArea viewText;
	private TextArea sendText;
	private DatagramSocket socket;
	private BufferedWriter bw;
	/**
	 * @param args
	 * GUI聊天
	 */
	
	public static void main(String[] args) {
		new udp_gui();
	}

	public udp_gui() {
		init();
		southPanel();
		centerPanel();
		event();
	}

	public void event() {
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				try {
					socket.close();
					bw.close();
				} catch (IOException e1) {
					
					e1.printStackTrace();
				}
				System.exit(0);
			}
		});
		
		send.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					send();
				} catch (IOException e1) {
					
					e1.printStackTrace();
				}
			}

		});
		
		log.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					logFile();
				} catch (IOException e1) {
					
					e1.printStackTrace();
				}
			}

		});
		
		clear.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				viewText.setText("");
			}
		});
		
		shake.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					send(new byte[]{-1},tf.getText());
				} catch (IOException e1) {
					
					e1.printStackTrace();
				}
			}

		});
		
		sendText.addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent e) {
				//if(e.getKeyCode() == KeyEvent.VK_ENTER && e.isControlDown()) {	//isControlDown ctrl是否被按下
				if(e.getKeyCode() == KeyEvent.VK_ENTER) {
					try {
						send();
					} catch (IOException e1) {
						
						e1.printStackTrace();
					}
				}
			}
		});
	}
	

	private void shake() {
		int x = this.getLocation().x;							//获取横坐标位置
		int y = this.getLocation().y;							//获取纵坐标位置
		
		for(int i = 0; i < 20; i++) {
			try {
				this.setLocation(x + 20, y + 20);
				Thread.sleep(20);
				this.setLocation(x + 20, y - 20);
				Thread.sleep(20);
				this.setLocation(x - 20, y + 20);
				Thread.sleep(20);
				this.setLocation(x - 20, y - 20);
				Thread.sleep(20);
				this.setLocation(x, y);
			} catch (InterruptedException e) {
				
				e.printStackTrace();
			}
		}
	}
	
	private void logFile() throws IOException {
		bw.flush();									//刷新缓冲区
		FileInputStream fis = new FileInputStream("config.txt");
		ByteArrayOutputStream baos = new ByteArrayOutputStream();	//在内存中创建缓冲区
		
		int len;
		byte[] arr = new byte[8192];
		while((len = fis.read(arr)) != -1) {
			baos.write(arr, 0, len);
		}
		
		String str = baos.toString();				//将内存中的内容转换成了字符串
		viewText.setText(str);
		
		fis.close();
	}
	
	private void send(byte[] arr, String ip) throws IOException {
		DatagramPacket packet = 
				new DatagramPacket(arr, arr.length, InetAddress.getByName(ip), 9999);
		socket.send(packet);						//发送数据
	}
	
	private void send() throws IOException {
		String message = sendText.getText();		//获取发送区域的内容
		String ip = tf.getText();					//获取ip地址;
		ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;
		
		send(message.getBytes(),ip);
		
		String time = getCurrentTime();				//获取当前时间
		String str = time + " 我对:" + (ip.equals("255.255.255.255") ? "所有人" : ip) + "说\r\n" + message + "\r\n\r\n";	//alt + shift + l 抽取局部变量
		viewText.append(str);						//将信息添加到显示区域中
		bw.write(str);								//将信息写到数据库中
		sendText.setText("");
		
		
	}
	
	private String getCurrentTime() {
		Date d = new Date();						//创建当前日期对象
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
		return sdf.format(d);						//将时间格式化
	}

	public void centerPanel() {
		Panel center = new Panel();					//创建中间的Panel
		viewText = new TextArea();
		sendText = new TextArea(5,1);
		center.setLayout(new BorderLayout());		//设置为边界布局管理器
		center.add(sendText,BorderLayout.SOUTH);	//发送的文本区域放在南边
		center.add(viewText,BorderLayout.CENTER);	//显示区域放在中间
		viewText.setEditable(false);				//设置不可以编辑
		viewText.setBackground(Color.WHITE);		//设置背景颜色
		sendText.setFont(new Font("xxx", Font.PLAIN, 15));
		viewText.setFont(new Font("xxx", Font.PLAIN, 15));
		this.add(center,BorderLayout.CENTER);
	}

	public void southPanel() {
		Panel south = new Panel();					//创建南边的Panel
		tf = new TextField(15);
		tf.setText("127.0.0.1");
		send = new Button("发 送");
		log = new Button("记 录");
		clear = new Button("清 屏");
		shake = new Button("震 动");
		south.add(tf);
		south.add(send);
		south.add(log);
		south.add(clear);
		south.add(shake);
		this.add(south,BorderLayout.SOUTH);			//将Panel放在Frame的南边
	}

	public void init() {
		this.setLocation(500, 50);
		this.setSize(400, 600);
		new Receive().start();
		try {
			socket = new DatagramSocket();
			bw = new BufferedWriter(new FileWriter("config.txt",true));	//需要在尾部追加
		} catch (Exception e) {
			
			e.printStackTrace();
		}
		this.setVisible(true);
	}
	private class Receive extends Thread {			//接收和发送需要同时执行,所以定义成多线程的
		public void run() {
			try {
				DatagramSocket socket = new DatagramSocket(9999);
				DatagramPacket packet = new DatagramPacket(new byte[8192], 8192);
				
				while(true) {
					socket.receive(packet);				//接收信息
					byte[] arr = packet.getData();		//获取字节数据
					int len = packet.getLength();		//获取有效的字节数据
					if(arr[0] == -1 && len == 1) {		//如果发过来的数组第一个存储的值是-1,并且数组长度是1
						shake();						//调用震动方法
						continue;						//终止本次循环,继续下次循环,因为震动后不需要执行下面的代码
					}
					String message = new String(arr,0,len);	//转换成字符串
					
					String time = getCurrentTime();		//获取当前时间
					String ip = packet.getAddress().getHostAddress();	//获取ip地址
					String str = time + " " + ip + " 对我说:\r\n" + message + "\r\n\r\n";
					viewText.append(str);
					bw.write(str);
				}
			} catch (Exception e) {
				
				e.printStackTrace();
			}
		}
	}
	

}



测试成功
,把它打包成jar文件
对这个类右键 Export——java,jar file
然后next两次
在select  the class of application entry point  这个item下
main class 标签文字旁边 ,浏览选中我们这个类,finish
,就可以在安装java虚拟机的电脑上直接运行

注意
在打包jar是要在select the resources to export这个标签下
确认我们是否选中了需要打包的类.


5.TCP传输

ServerSocket

java.lang.Object ——java.net.ServerSocket 直接已知子类: SSLServerSocket  public class ServerSocket extends Object 此类实现服务器套接字。 服务器套接字等待请求通过网络传入。 它基于该请求执行某些操作,然后可能向请求者返回结果。 

public ServerSocket(int port) throws IOException
	创建绑定到特定端口的服务器套接字。
	端口 0 在所有空闲端口上创建套接字。 


public Socket accept() throws IOException
	侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。返回新的套接字


TCP协议案例


客户端
* 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
* 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
* 输入流可以读取服务端输出流写出的数据
* 输出流可以写出数据到服务端的输入流


public class a_client {

	/**
	 * @throws IOException 
	 * @throws UnknownHostException 
	 */
	public static void main(String[] args) throws UnknownHostException, IOException {
		Socket socket = new Socket("127.0.0.1", 12345);
		
		InputStream is = socket.getInputStream();//获取客户端输入流
		OutputStream os = socket.getOutputStream();	//获取客户端的输出流
		
		byte[] arr = new byte[1024];
		int len = is.read(arr);				//读取服务器发过来的数据
		System.out.println(new String(arr,0,len)); //将数据转换成字符串并打印
		
		os.write("学习java".getBytes());//客户端向服务器写数据
		
		socket.close();
	}

}


服务端
* 创建ServerSocket(需要指定端口号)
* 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
* 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
* 输入流可以读取客户端输出流写出的数据
* 输出流可以写出数据到客户端的输入流


public class b_server {

	/**
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		ServerSocket server = new ServerSocket(12345);

		Socket socket = server.accept();	//接受客户端的请求
		InputStream is = socket.getInputStream();//获取客户端输入流
		OutputStream os = socket.getOutputStream();//获取客户端的输出流
		
		os.write("百度一下你就知道".getBytes());//服务器向客户端写出数据
		
		byte[] arr = new byte[1024];
		int len = is.read(arr);			//读取客户端发过来的数据
		System.out.println(new String(arr,0,len)); //将数据转换成字符串并打印
		
		socket.close();
	}

}


TCP协议案例优化


客户端

public class c_client {

	/**
	 * @throws IOException 
	 * @throws UnknownHostException 
	 */
	public static void main(String[] args) throws UnknownHostException, IOException {
		Socket socket = new Socket("127.0.0.1", 12345);
		BufferedReader br = new BufferedReader(
				new InputStreamReader(socket.getInputStream()));//将字节流包装成了字符流
		PrintStream ps = new PrintStream(socket.getOutputStream());
		//PrintStream中有写出换行的方法
		//因为readline()方法时是需要"/r/n"换行符来来结束的
		
		System.out.println(br.readLine());
		ps.println("我想报名武术");//
		System.out.println(br.readLine());
		ps.println("大哭!!!能不能给次机会");
		
		socket.close();
	}

}


服务端

public class d_server {

	/**
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		
		/*ServerSocket server = new ServerSocket(12345);
		Socket socket = server.accept();//接受客户端的请求
		
		BufferedReader br = new BufferedReader(
				new InputStreamReader(socket.getInputStream()));//将字节流包装成了字符流
		PrintStream ps = new PrintStream(socket.getOutputStream());	
		//PrintStream中有写出换行的方法
		
		ps.println("欢迎咨询");
		System.out.println(br.readLine());
		ps.println("不好意思,满员了");
		System.out.println(br.readLine());
		socket.close();*/
		
		
		/*
		 * 服务端是多线程的
		 * */
		ServerSocket server = new ServerSocket(12345);
		while(true) {
			final Socket socket = server.accept();//接受客户端的请求
			new Thread() {
				public void run() {
					try {
						BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));		//将字节流包装成了字符流
						PrintStream ps = new PrintStream(socket.getOutputStream());					//PrintStream中有写出换行的方法
						
						ps.println("欢迎咨询");
						System.out.println(br.readLine());
						ps.println("不好意思,满员了");
						System.out.println(br.readLine());
						
						socket.close();
					} catch (IOException e) {
						
						e.printStackTrace();
					}
				}
			}.start();
		}
	}

}

ok



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值