Socket 又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。ServerSocket用于服务器端,Socket是建立网络连接时使用的。
在连接成功时,应用程序两端都会产生一个 Socket实例,通过操作这个实例,就可以完成相关的通讯和会话。
对于一个网络连接来说,套接字是平等的,并没有差别。
不管是Socket还是ServerSocket他们的工作都是通过socket类及其子类完成的。
Socket链接建立步骤: 相当于”三次握手”
1)服务器端监听连接请求、
2)客户端发出连接请求、
3)创建和确认连接
Socket特点:
1)Socket链接基于TCP通信协议,连接有保障;
2)Socket适用于建立长时间的链接;
3)Socket编程通常用于即时通讯;
网络编程三要素:IP、协议、端口。
如何建立与ServerSocket的链接以及如何使用ServerSocket?
在浏览器中输入127.0.0.1:65530 相当于访问本机的端口为65530的应用程序。
ServerSocket Socket accept() socket.getOutputStream()
package com.example.tuhuadmin.socketapplication;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by Tuhuadmin on 2016/7/15.
* 如何与ServerSocket建立连接以及SocketServer的使用
*/
public class TestMyServerSocket {
public static void main(String[] args) {
try {
//需要传入一个端口号
//创建ServerSocket时会有异常抛出
ServerSocket serverSocket = new ServerSocket(65530);
//创建完成后,要监听客户端的连接请求,所以要调用它的阻塞方法accept();accept是阻塞方法,他会阻塞当前线程的执行,肯定不能放在主线程里面。
Socket socket = serverSocket.accept();
//一旦accept()被执行,表示有客户端连接上,就会产生一个服务器端的socket与之进行通讯
System.out.print("有客户端连接到本机!");
//在浏览器中输入127.0.0.1:65530 回车就可以看到输出的信息
} catch (IOException e) {
e.printStackTrace();
}
}
}
简单的聊天服务器代码:
package com.example.tuhuadmin.socketapplication;
/**
* Created by Tuhuadmin on 2016/7/15.
* 使用socket建立聊天服务器
*/
public class TestMyServerSocket {
public static void main(String[] args) {
//开启服务器端网络连接监听的线程
new ServerListener().start();
//在dos命令面板中输入 telnet localhost 65531,服务器端就可以收到,病打印输出语句。
//实现聊天室的功能:将服务器端所有的通讯线程保存到一个集合当中,当有用户发来数据,则转发给所有用户,实现聊天室效果。
}
}
package com.example.tuhuadmin.socketapplication;用于聊天的socket处理 业务逻辑
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by Tuhuadmin on 2016/7/15.
*/
public class ServerListener extends Thread {
@Override
public void run() {
try {
//需要传入一个端口号
//创建ServerSocket时会有异常抛出
ServerSocket serverSocket = new ServerSocket(65531);
//创建完成后,要监听客户端的连接请求,所以要调用它的阻塞方法accept();accept是阻塞方法,他会阻塞当前线程的执行,肯定不能放在主线程里面。
while (true) {
Socket socket = serverSocket.accept();
//需要将socket传递给新的线程与服务器端进行通讯, 创建用于socket通讯的线程。
ChatSocket chatSocket = new ChatSocket(socket);
chatSocket.start();
ChatManager.getChatManager().addChatSocket(chatSocket);
// 此时每一个ChatSocket都是独立的线程,他们不能相互传递数据。
}
//一旦accept()被执行,表示有客户端连接上,就会产生一个服务器端的socket与之进行通讯
//每一个客户端的连接,都会返回一个Socket对象,所以要创建一个while循环,循环监听客户端的连接
} catch (IOException e) {
e.printStackTrace();
}
//对于有阻塞的方法(耗时操作),要把它放置到独立的线程中
}
}
package com.example.tuhuadmin.socketapplication;管理所有的聊天Socket
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
/**
* Created by Tuhuadmin on 2016/7/15.
* 创建用于和客户端通讯的socket
*/
public class ChatSocket extends Thread {
//为此类创建一个构造方法,并传入需要通讯的socket
private Socket socket;
public ChatSocket(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//在当前的线程中,要对当前的socket输出功能进行包装
out("你已经连接到本服务器了");
try {
//获取socket的输出流,通过输出流才可以向外输出数据。
// OutputStream outputStream = socket.getOutputStream();
// BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
//让当前的socket循环输出 指定编码集
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
String line;
//循环执行读取数据的工作
while ((line = bufferedReader.readLine()) != null) {
//说明当前读取到了数据
ChatManager.getChatManager().sendMessage(this, line);
}
//关闭当前流
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void out(String str) {
try {
socket.getOutputStream().write((str+"\n").getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package com.example.tuhuadmin.socketapplication;
import java.util.Vector;
/**
* Created by Tuhuadmin on 2016/7/15.
*/
public class ChatManager {
//我们需要新建一个类,将每一个ChatSocket管理起来,然后实现他们之间的通讯
//由于一个聊天服务器只能有一个ChatManager,所以此ChatManager应该是单利模式
//单例模式:构造函数私有,不让创建对象;对外提供一个获取对象的方法
private static final ChatManager chatManager = new ChatManager();
//创建一个集合去管理
Vector<ChatSocket> vector = new Vector<ChatSocket>();
private ChatManager() {
}
public static ChatManager getChatManager() {
return chatManager;
}
//提供一个方法,把所有的ChatSocket添加到ChatMananger里面
public void addChatSocket(ChatSocket chatSocket) {
vector.add(chatSocket);
}
//其中的一个ChatSocket可以通过调用此方法和其他的ChatSocket进行通讯
//把线程本身传递进来,传入当前需要发送的信息
public void sendMessage(ChatSocket chatSocket, String message) {
//既然要发送给集合中所有的通讯线程,就需要对集合进行遍历
for (int i = 0; i < vector.size(); i++) {
//在这里进行判断,因为当前发送信息的线程,就不需要接收信息了,
ChatSocket cs = vector.get(i);
if (!cs.equals(chatSocket)) {
cs.out(message);
}
}
}
} </span>