一、多发多收
客户端:
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class Test1_2 {
public static void main(String[] args) throws IOException {
//TCP发送端
Scanner sc=new Scanner(System.in);
String b;
//创建Socket对象
Socket socket=new Socket("127.0.0.1",1000);
OutputStream ops = socket.getOutputStream();
//多次发送数据
while(true){
//从连接通道中获取输出流
System.out.print("输入信息:");
b=sc.nextLine();
ops.write((b+"\r\n").getBytes());
ops.flush();
if(b.equals("886"))
break;
}
socket.close();
}
}
服务器:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Test1 {
public static void main(String[] args) throws IOException {
//TCP接收端
//创建ServerSocket对象
ServerSocket ss=new ServerSocket(1000);
//接收数据
Socket socket = ss.accept();
//获取通道中的输入流
InputStreamReader isr=new InputStreamReader(socket.getInputStream());
int b;
//多发多收
while ((b = isr.read()) != -1) {
System.out.print((char)b);
}
socket.close();
ss.close();
}
}
Tips:
BufferedWriter
OutputStreamWriter 这类因为自身带有缓冲区,因此只有当缓冲区填满时或者流关闭时才会向服务器传输数据。不适合多发多收。
二、接收和反馈
客户端:
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class Test2_2 {
public static void main(String[] agrs) throws IOException {
//TCP协议发送端
//创建Socket对象
//在创建对象的同时会连接服务器
//如果连接不上,代码会报错
Socket socket=new Socket("127.0.0.1",1000);
//从连接通道种获取输出流
OutputStream ops=socket.getOutputStream();
Scanner sc=new Scanner(System.in);
//写出数据
String s=sc.nextLine();
ops.write(s.getBytes());
//关闭通道中输出流
socket.shutdownOutput();
//等待接收端反馈信息
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str = br.readLine();
System.out.println(str);
socket.close();
}
}
服务器:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Test2 {
public static void main(String[] args) throws IOException {
//TCP协议接收端
//创建ServerSocket对象
ServerSocket ss=new ServerSocket(1000);
//监听客户端的链接
Socket socket=ss.accept();
//从连接通道中获取输入流,读取数据(不能传中文)
//使用转换流转化为字符流
InputStreamReader isr=new InputStreamReader(socket.getInputStream());
//为了读取效率,再套一个缓冲流
BufferedReader br=new BufferedReader(isr);
String s;
while((s=br.readLine())!=null){
System.out.println(s);
}
//关闭通道中的输入流
socket.shutdownInput();
//反馈
//获取通道中的输出流
socket.getOutputStream();
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("已经接收到了信号");
bw.close();
socket.close();
}
}
Tips:
//读取结束标记 socket.shutdownInput();
//写入结束标记 socket.shutdownOutput(); 通道中的输出流和输入流两边都可以调取并使用
三、上传文件
客户端:
import java.io.*;
import java.net.Socket;
public class Test3_2 {
public static void main(String[] args) throws IOException {
//发送端
//创建Socket对象
Socket socket=new Socket("127.0.0.1",1000);
OutputStream ops=socket.getOutputStream();
//根据通道输出流转换成字符流再转换成字符缓冲流
BufferedOutputStream bos=new BufferedOutputStream(socket.getOutputStream());
//读取本地文件
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("src\\MIUI10.jpg"));
int len;
byte[] bytes=new byte[1024];
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
bos.flush(); //刷新缓冲区
}
//本地文件读取结束
bis.close();
//输出流结束标记
socket.shutdownOutput();
//接收反馈信号
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String b;
while((b=br.readLine())!=null){
System.out.println(b);
}
br.close();
socket.close();
}
}
服务器:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Test3 {
public static void main(String[] args) throws IOException {
//接收端
//创建服务器对象
ServerSocket ss=new ServerSocket(1000);
//通道对象
Socket socket = ss.accept();
//获取通道的输入流
BufferedInputStream bis=new BufferedInputStream(socket.getInputStream());
//写入本地文件
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("COPY.jpg"));
int len;
byte[] bytes=new byte[1024];
while((len=bis.read(bytes))!=-1){
//拷贝
bos.write(bytes,0,len);
bos.flush();//刷新缓冲区
}
bos.close();
//读取结束标志
socket.shutdownInput();
//发送反馈
//获取通道中的输出流
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("文件接收完毕");
bw.close();//刷新缓冲区
//释放资源
socket.close();
}
}
四、解决三中重名问题
只需要修改服务器
服务器:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
public class Test3 {
public static void main(String[] args) throws IOException {
//接收端
//创建服务器对象
ServerSocket ss=new ServerSocket(1000);
//通道对象
Socket socket = ss.accept();
//获取通道的输入流
BufferedInputStream bis=new BufferedInputStream(socket.getInputStream());
//写入本地文件
String name=UUID.randomUUID().toString().replace("-","");
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(name+".jpg"));
int len;
byte[] bytes=new byte[1024];
while((len=bis.read(bytes))!=-1){
//拷贝
bos.write(bytes,0,len);
bos.flush();//刷新缓冲区
}
bos.close();
//读取结束标志
socket.shutdownInput();
//发送反馈
//获取通道中的输出流
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("文件接收完毕");
bw.close();//刷新缓冲区
//释放资源
socket.close();
}
}
Tips:
String name=UUID.randomUUID().toString().replace("-",""); BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(name+".jpg")); UUID类中的randomUUID方法:生成随机且唯一的序列号
五、上传文件(多线程版)
服务器:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Test5 {
public static void main(String[] args) throws IOException {
//接收端
//创建服务器对象
ServerSocket ss=new ServerSocket(1000);
while(true){
//阻塞状态:等待客户端连接
Socket socket = ss.accept();
new MyThread(socket).start();
}
}
}
线程对象:
import java.io.*;
import java.net.Socket;
import java.util.UUID;
public class MyThread extends Thread{
private Socket socket;
public MyThread(Socket socket){
this.socket=socket;
}
@Override
public void run() {
//通道对象
try {
//获取通道的输入流
BufferedInputStream bis = new BufferedInputStream(this.socket.getInputStream());
//写入本地文件
String name = UUID.randomUUID().toString().replace("-", "");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(name + ".jpg"));
int len;
byte[] bytes = new byte[1024];
while ((len = bis.read(bytes)) != -1) {
//拷贝
bos.write(bytes, 0, len);
bos.flush();//刷新缓冲区
}
bos.close();
//读取结束标志
this.socket.shutdownInput();
//发送反馈
//获取通道中的输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(this.socket.getOutputStream()));
bw.write("文件接收完毕");
bw.close();//刷新缓冲区
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//释放资源
if(socket!=null){
//避免空指针异常
//若socket为null 对其调用close方法,则会导致空指针异常
try {
this.socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
六、上传文件(线程池版)
服务器:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Test6 {
public static void main(String[] args) throws IOException {
//接收端
//创建线程池对象
ThreadPoolExecutor pool=new ThreadPoolExecutor(
3,//核心线程数量 不能小于0
16,//最大线程数 不能小于0,最大数量必须要大于等于核心数量
60,//空闲线程的最大存活时间
TimeUnit.SECONDS,//时间单位
new ArrayBlockingQueue<>(3),//任务队列
Executors.defaultThreadFactory(),//创建线程工厂
new ThreadPoolExecutor.AbortPolicy() //创建任务的拒绝策略(新建一个类的内部类)
);
//创建服务器对象
ServerSocket ss=new ServerSocket(1000);
while(true){
//阻塞状态:等待客户端连接
Socket socket = ss.accept();
//添加入线程池
pool.submit(new MyThread(socket));
}
}
}
七、多人聊天室
客户端:
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class TalkRoom_client {
public static void main(String[] args) throws IOException {
//客户端
//创建Socket对象
Socket socket=new Socket("127.0.0.1",1000);
while(true){
show();
Scanner sc = new Scanner(System.in);
String choose = sc.nextLine();
if (choose.equals("1")) {
//登录选择
Login(socket);
} else if (choose.equals("2")) {
//注册
Register(socket);
} else {
//选择不对
System.out.println("无效选择,请输入 1 或 2 ");
}
}
}
private static void Register(Socket socket) throws IOException {
Scanner sc=new Scanner(System.in);
//向服务器传输注册标志
SendMessageToClient(socket,"register");
while(true){
//开始注册流程
showRegister();
System.out.print("请输入账号:");
String account=sc.nextLine();
System.out.println("请输入密码:");
String password=sc.nextLine();
int result=check(account,password);
//1 正确 2 账号错误 3 密码错误
if(result==1){
//正确,进行传输
String str=account+"="+password;
SendMessageToClient(socket,str);
System.out.println("注册成功");
break;
}else if(result==2){
//账号违法
System.out.println("账号违法,请重新注册");
}else{
//密码违法
System.out.println("密码违法,请重新注册");
}
}
}
public static void TalkToAll(Socket socket) throws IOException {
Scanner sc=new Scanner(System.in);
System.out.println("开始聊天");
while(true){
System.out.println("请输入要说的话:");
String str=sc.nextLine();
SendMessageToClient(socket,str);
}
}
public static int check(String account,String password){
if(account.matches("[a-zA-Z]{6,12}")){
if(password.matches("[a-zA-Z]\\d{2,7}")){
//全对
return 1;
}else{
//密码不对
return 3;
}
}else return 2; //账号不对
}
public static void Login(Socket socket) throws IOException {
Scanner sc=new Scanner(System.in);
//字符缓冲流:用于传输账号密码信息
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//向服务器传输登录标志
bw.write("login");
bw.newLine();
bw.flush();
System.out.println("请输入您的账号:");
String account = sc.nextLine();
bw.write(account);
bw.write("&");
System.out.println("请输入您的密码:");
String password = sc.nextLine();
bw.write(password);
bw.newLine();
bw.flush();
//接收反馈
String s = br.readLine();
System.out.println("结果为:"+s);
//1 登录成功 2 密码错误 3 账号不存在
if("1".equals(s)){
System.out.println("登录成功");
new ReceiveMessage(socket).start();
//开始聊天
TalkToAll(socket);
}else if("2".equals(s)){
System.out.println("密码错误");
}else {
System.out.println("账号不存在");
}
}
public static void SendMessageToClient(Socket socket,String str) throws IOException {
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(str);
bw.newLine();
bw.flush();
}
public static void show(){
System.out.println("=======聊天室========");
System.out.println("1、登录");
System.out.println("2、注册");
System.out.println("请输入您的选择:");
}
public static void showRegister(){
System.out.println("开始注册");
System.out.println("账号要求:6~12位,纯字母");
System.out.println("密码要求:3~8位,第一位必须为字母,其余纯数字");
}
}
服务器:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class TalkRoom_server {
public static void main(String[] args) throws IOException {
//创建服务器
ServerSocket ss=new ServerSocket(1000);
//创建一个存放socket的集合来进行统一操作
ArrayList<Socket> socketlist=new ArrayList<>();
while(true){
//等待客户端连接
Socket socket = ss.accept();
socketlist.add(socket);
new ClientThread(socket,socketlist).start();
}
}
}
客户端线程:
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class ClientThread extends Thread{
static File file=new File("tst.txt"); //存放账号信息的本地文件
private Socket socket;
private ArrayList<Socket> socketlist;
private Map<String,String> map=new HashMap<>();
public ClientThread(Socket socket,ArrayList<Socket> socketlist){
this.socket=socket;
this.socketlist=socketlist;
}
public void updateMap() throws IOException {
//读取本地文件中的账号信息存入集合中
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(new FileInputStream("tst.txt")));
String b;
while((b=bufferedReader.readLine())!=null){
String[] strings = b.split("=");
map.put(strings[0],strings[1]);
}
}
@Override
public void run() {
while(true){
try {
//接收用户传过来的信息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//第一次传输的是选择
String choose = br.readLine();
switch (choose) {
case "login":
System.out.println("用户选择登录");
//登录操作
//先更新本地文件map
updateMap();
login(br, socket, map);
break;
case "register":
//注册操作
System.out.println("用户选择注册");
register(br,socket,file);
break;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public void register(BufferedReader br,Socket socket,File file) throws IOException {
//接收传过来的注册信息
String b=br.readLine();
//写入本地文件
BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file,true)));
bufferedWriter.write(b);
bufferedWriter.newLine();
bufferedWriter.close();
//更新本地文件
updateMap();
}
public void login(BufferedReader br,Socket socket,Map<String,String> map) throws IOException {
ArrayList<String> list=new ArrayList<>();
//获取传输过来的账号密码信息
String info=br.readLine(); //account&password
String[] split = info.split("&");
System.out.println("用户输入账号为:"+split[0]);
System.out.println("用户输入密码为:"+split[1]);
list.add(split[0]);
list.add(split[1]);
if(map.get(list.get(0))!=null){
//账号存在
if(map.get(list.get(0)).equals(list.get(1))){
//密码正确
System.out.println("用户"+list.get(0)+"登录成功");
SendMessageToClient("1");
//开始聊天
//接收
ReceiveMessageFromClient(list.get(0),socketlist);
}else {
//密码错误
System.out.println("密码错误");
SendMessageToClient("2");
}
}else{
//根本不存在账号
System.out.println("账号不存在");
SendMessageToClient("3");
}
}
public void SendMessageToClient(String str,ArrayList<Socket> socketlist) throws IOException {
for (Socket s : socketlist) {
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw.write(str);
bw.newLine();
bw.flush();
}
}
public void SendMessageToClient(String str) throws IOException {
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(str);
bw.newLine();
bw.flush();
}
public void ReceiveMessageFromClient(String name,ArrayList<Socket> socketlist) throws IOException {
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String b;
while((b=br.readLine())!=null){
System.out.println("用户"+name+"发送了信息:"+b);
//广播给所有用户
SendMessageToClient("用户"+name+"发送了信息:"+b,socketlist);
}
}
}