TCP: ( Transmission Control Protocol) 传输控制协议,采用三方握手的方式,保证准确的连接操作。
UDP: (User Datagram Protocol) 数据报协议,发送数据报,例如:手机短信或者是QQ消息。
TCP、UDP的数据帧格式简单关系(其中协议类型用于区分TCP、UDP):
协议类型源IP | 目标P | 源端口目标端口 | 帧序号 | 帧数据
Echo,意为应答,程序的功能是客户端向服务器发送一个字符串, 服务器不做任何处理,直接把字符串返回给客户端,Echo程序是最为网络编程的HelloWorlld。就是最基本的客户端/服务端程序。
服务端
package echo;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo {
public static void main(String[] args) {
/**
* 创建一个服务端的Socket(1024-15535)
*/
try {
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("服务器已启动,正在等待客户端的链接...");
//等待客户端的链接,造成阻塞,如果有客户端连接成功就返回一个Socket对象
Socket socket = serverSocket.accept();
System.out.println("建立连接成功--->"+socket.getLocalAddress());
/**
* IO传输
*/
//通过输入流读取网络数据,
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str = br.readLine();//在此处,如果没有数据就会造成阻塞
System.out.println("数据获取成功!");
//获取输出流,向客户端返回消息
PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
ps.print("Echo:"+str);
ps.flush();
System.out.println("数据已返回客户端!");
//关闭流
br.close();
ps.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端
package echo;
import java.io.*;
import java.net.Socket;
public class ClientDemo {
public static void main(String[] args) {
/**
* 创建一个Socket对象,指定一个服务器对象
*/
try {
Socket socket = new Socket("127.0.0.1",6666);
/**
* IO传输
*/
//获取Socket的输入输出流
PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//传输的消息
ps.println("Hello Socket!");
ps.flush();
//从服务端接受到的消息
String str = br.readLine();
System.out.println(str);
//关闭流
ps.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:
应答程序多线程实现,能让一个服务器处理多个客户端
服务端:
package echo;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//处理多个客户端信息
//主线程用来监听线程的连接,每次有连接成功就让线程池中的线程去处理任务
public class MultipleServerDemo {
public static void main(String[] args) {
//线程池
ExecutorService es = Executors.newFixedThreadPool(3);
try {
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("服务器已启动!正在等待连接...");
//反复接受多个客户端的请求
while (true){
Socket s = serverSocket.accept();
System.out.println(s.getLocalAddress());
es.execute(new UserThread(s));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 用来处理客户端请求的线程任务
*/
class UserThread implements Runnable{
private Socket s;
public UserThread(Socket s){
this.s = s;
}
@Override
public void run() {
try {
//读
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//写
PrintStream ps = new PrintStream(new BufferedOutputStream(s.getOutputStream()));
String s = br.readLine();
System.out.println(s);
ps.println("Echo:"+s);
ps.flush();
br.close();
ps.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端:
package echo;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class MultipleClientDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
/**
* 创建一个Socket对象,指定一个服务器对象
*/
try {
Socket socket = new Socket("127.0.0.1",6666);
/**
* IO传输
*/
//获取Socket的输入输出流
PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//传输的消息
System.out.println("请输入消息:");
String info = scanner.nextLine();
ps.println(info);
ps.flush();
//从服务端接受到的消息
info = br.readLine();
System.out.println(info);
//关闭流
ps.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端与客户端之间的通信 ,即服务器端用于转发通信
MgsType类
package clientToClient;
public final class MgsType {
public static final int LOGIN = 0x1;//登录消息类型
public static final int MSG = 0x2;//发送消息类型
}
Message类
package clientToClient;
import java.io.Serializable;
public class Message implements Serializable {//继承可序列化
private String from;//谁发的
private String to;//发给谁
private int type;//消息类型
private String info;//消息内容
public Message() {
}
public Message(String from, String to, int type, String info) {
this.from = from;
this.to = to;
this.type = type;
this.info = info;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
Client类
package clientToClient;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Client {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
ExecutorService es = Executors.newSingleThreadExecutor();//单个线程
try {
Socket socket = new Socket("127.0.0.1",8911);
System.out.println("与服务器建立连接成功");
//流
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());//写
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());//读
System.out.println("请输入名称:");
String name = sc.nextLine();
Message msg = new Message(name, null, MgsType.LOGIN, null);
oos.writeObject(msg);
msg = (Message) ois.readObject();
System.out.println(msg.getFrom()+msg.getInfo());
//启动读取消息的线程
es.execute(new SendMsgByClient(ois));
//使用主线程发送消息
while (true){
msg = new Message();
System.out.println("To:");
msg.setTo(sc.nextLine());
msg.setFrom(name);
msg.setType(MgsType.MSG);
System.out.println("Info:");
msg.setInfo(sc.nextLine());
oos.writeObject(msg);
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class SendMsgByClient implements Runnable{
private ObjectInputStream ois;//读取
private boolean flag = true;
public SendMsgByClient(ObjectInputStream ois) {
this.ois = ois;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
while (flag) {
Message msg = (Message) ois.readObject();
System.out.println("["+msg.getFrom()+"]对你说:"+msg.getInfo());
}
if(ois !=null){
ois.close();
}
}catch (IOException | ClassNotFoundException e){
e.printStackTrace();
}
}
}
Server类
package clientToClient;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
public static void main(String[] args) {
//用于存储开启的客户端
Vector<UserThread> vector = new Vector();
ExecutorService es = Executors.newFixedThreadPool(3);//可最大连接3个客户端
//创建服务器
try {
ServerSocket ss = new ServerSocket(8911);
System.out.println("服务器已开启,正在等待连接...");
while (true){
Socket socket = ss.accept();
UserThread user = new UserThread(socket, vector);
es.execute(user);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 客户端处理的线程
*/
class UserThread implements Runnable{
private String name;//用于记录客户端的名字
private Socket socket;//客户端的socket
private Vector<UserThread> vector;//客户端处理线程的集合
//流
private ObjectInputStream ois;
private ObjectOutputStream oos;
private boolean flag = true;
public UserThread(Socket socket,Vector vector){
this.socket = socket;
this.vector = vector;
//将这个线程添加到集合中
vector.add(this);
}
@Override
public void run() {
System.out.println("客户端-->"+socket.getLocalAddress()+"已连接!");//通知已连接
try {
//流的对象
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
//读取消息对象
while (flag) {
Message msg = (Message) ois.readObject();
int type = msg.getType();
switch (type){
case MgsType.MSG:
int size = vector.size();//待会从集合中遍历找出发送对象
String to = msg.getTo();//发送给谁的
UserThread ut;
for (int i=0;i<size;i++){
ut = vector.get(i);
if(to.equals(ut.name) && ut!=this){
ut.oos.writeObject(msg);
break;
}
}
break;
case MgsType.LOGIN:
name = msg.getFrom();
msg.setInfo("欢迎您!");
oos.writeObject(msg);
break;
}
}
//关闭流
ois.close();
oos.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
结果: