基于TCP协议,面向连接,效率低,但安全性高
1.例子:建立服务器与客户端,实现通信(该例子服务器只可以接受一个客户端连接)
/*
* 服务器端serverSocket
*/
@Test
public void test5() throws IOException {
ServerSocket server=new ServerSocket(9999);
Socket socket=server.accept(); //返回服务器与客户端的连接Socket(阻塞式,无连接不向下运行)
System.out.println("创建一个连接!"); //此时可直接用浏览器访问localhost:9999
String msg="你好!欢迎访问";
DataOutputStream dos=new DataOutputStream(socket.getOutputStream());
dos.writeUTF(msg);
dos.flush();
dos.close();
}
/*
* 客户端socket(与UDP不同,不用指定客户端端口)
*/
@Test
public void test6() throws UnknownHostException, IOException {
Socket client=new Socket("localhost",9999); //指定的式服务器的ip和端口,此时就以建立连接
DataInputStream dis=new DataInputStream(client.getInputStream());
String s=dis.readUTF();
System.out.println(s);
}
2.例子:聊天室(实现群聊和私聊,每个用户登录时的提示)
1)服务器类:
public class Server2 {
//用来统一管理所有的客户端连接
List<MySocket> list=new ArrayList<>();
/*
* 启动服务器:
* 1.建立服务器
* 2.无限循环等待接受连接,若连接上将其将入管理list,建立新的线程
*/
public void startt() throws IOException {
ServerSocket server=new ServerSocket(8888);
while(true) {
Socket client=server.accept();
MySocket my=new MySocket(client);
list.add(my);
new Thread(my).start();
}
}
public static void main(String[] args) {
try {
new Server2().startt();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* 内部客户端连接类
*/
class MySocket implements Runnable{
//每个客户端了连接都有一个自己的输入输出流
boolean flag=true;
DataInputStream dis;
DataOutputStream dos;
String name;
public MySocket(Socket client) {
try {
dis=new DataInputStream(client.getInputStream());
dos=new DataOutputStream(client.getOutputStream());
name=dis.readUTF();
send("欢迎"+name+"登录"); //调用自己通道的send方法,发送给自己的客户端
sendOthers(name+"进入聊天室"); //通知其他用户该用户进入
} catch (IOException e) {
finish();
}
}
public void finish() {
flag=false;
CloseUtils.closeAll(dis,dos);
list.remove(this); //若出现错误,将自己从管理器中移除
}
public String recieve() {
String s=null;
try {
s=dis.readUTF();
} catch (IOException e) {
finish();
}
return s;
}
public void send(String s) {
try {
dos.writeUTF(s);
dos.flush();
} catch (IOException e) {
finish();
}
}
/*
* 分为群发和私聊
*/
public void sendOthers(String s) {
if(s.startsWith("@")) {
String name=s.substring(1,s.indexOf(":"));
String content=s.substring(s.indexOf(":")+1);
for(MySocket temp:list) {
if(temp.name.equals(name)) {
temp.send("[私聊]"+content);
break;
}
}
}else {
for(MySocket temp:list) {
if(temp==this) continue;
temp.send("[群发]"+s);
}
}
}
@Override
public void run() {
while(flag) {
String s=recieve();
sendOthers(s);
}
}
}
}
2)客户端类
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket client=new Socket("localhost", 8888);
System.out.println("请输入姓名");
String name=new Scanner(System.in).nextLine();
//如果不使用多线程,客户端只有发送完信息以后才可以接受信息
new Thread(new Send(client,name)).start();
new Thread(new Recieve(client)).start();
}
}
3)客户端中接受线程
public class Recieve implements Runnable{
DataInputStream dis;
boolean isRunning=true;
public Recieve(Socket client) {
try {
dis=new DataInputStream(client.getInputStream());
} catch (IOException e) {
isRunning=false;
CloseUtils.closeAll(dis);
}
}
public String recieve() {
String msg="";
try {
msg=dis.readUTF();
} catch (IOException e) {
isRunning=false;
CloseUtils.closeAll(dis);
}
return msg;
}
@Override
public void run() {
while(isRunning) {
System.out.println(recieve());
}
}
}
4)客户端中发送线程
public class Send implements Runnable{
//控制台输入流
BufferedReader br;
//socket输出流
DataOutputStream dos;
boolean isRunning=true;
public Send(Socket client,String name) {
br=new BufferedReader(new InputStreamReader(System.in));
try {
dos=new DataOutputStream(client.getOutputStream());
dos.writeUTF(name);
dos.flush();
} catch (IOException e) {
isRunning=false;
CloseUtils.closeAll(br,dos);
}
}
public void send() {
String s;
try {
s = br.readLine();
} catch (IOException e) {
s="";
}
if(s!=null||!s.equals("")) {
try {
dos.writeUTF(s);
dos.flush();
} catch (IOException e) {
isRunning=false;
CloseUtils.closeAll(br,dos);
}
}
}
@Override
public void run() {
while(isRunning) {
send();
}
}
}