socket编程
1、准备工作
eclipse java
2、java支持网络编程,并且已经将其封装在java.net下,主要两个类,ServerSocket作为服务器端监听启动端口(1024-65535,0-1024系统占用),与客户端连接通信的类。Socket(套接字)表示一个连接,可以使用构造器Socket(String ip,int port)连接服务器,并且与之通信的类。
3、这里学习的是单服务器单个客户端的通信,多客服端单服务器的通信。
对于单对单的通信来说,服务器通过输入流接收到了客服端的请求之后,将消息处理,通过输出流发送到客服端,所以服务器端只需要一个监听客户端输入的线程,服务器如果需要单独一个线程监听服务器输入(如想通过Console控制服务器的启停),则应再启动一个线程。客服端通过Socket构造器连接服务器之后,获取IO流,应该启动两个线程一个监听服务器输入,一个监听客服端输入(如键盘打印)。
对于多对单来说,客服端差不多,但是在服务器端应该一直监听客服端的连接,并且每个连接都需要被监听,同时将每个连接放入一个map集合里面。当客服端想与客服端通信时,就可以同个map取得连接,获取输出流,将消息发送到想通信的客户端
4、注意:socket的关闭,会导致相对应的socket的关闭,socket关闭时同时会将输入输出流关系,向输出流输出数据时,一定要加上结束标志(pw.println(),pw.print(msg+"\r\n")),否则对应的输入流在read或者readline会出现异常。
5、代码
客户端
public class Client implements Runnable{
//1、创建客户端Socket,指定服务器地址和端口
private static Socket socket =null;
private static boolean isStop = false;
static {
try {
socket = new Socket(InetAddress.getLocalHost(),10086);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 搭建客户端
public static void main(String[] args) throws IOException {//客户端
//2、获取输出流,向服务器端发送信息
PrintWriter pw =new PrintWriter(socket.getOutputStream());//将输出流包装成打印流
BufferedReader keyIn = new BufferedReader(new InputStreamReader(System.in));
Thread t = new Thread(new Client());
t.start();
while(true) {
String info = keyIn.readLine();
if("end".equals(info)) {
isStop = true;
pw.println("end");
pw.flush();
break;
}else {
pw.write(info + System.getProperty("line.separator"));
pw.flush();
}
}
//socket.shutdownOutput();
//4、关闭资源
socket.close();
}
@Override
public void run() {
//3、获取输入流,并读取服务器端的响应信息
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(true){
String info=br.readLine();
System.out.println("我是客户端,服务器说:"+info);
if(isStop) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
服务器
public class SocketService {
public static void main(String[] args) throws Exception {
//1、创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
ServerSocket serverSocket =new ServerSocket(10086);//1024-65535的某个端口
//2、调用accept()方法开始监听,等待客户端的连接,进程阻塞
Socket socket = serverSocket.accept();
//3、获取输入流,并读取客户端信息
BufferedReader br =new BufferedReader(new InputStreamReader(socket.getInputStream()));
//4、获取输出流,响应客户端的请求
PrintWriter pw = new PrintWriter(socket.getOutputStream());
while(true){
String info=br.readLine();
//处理消息
System.out.println("我是服务器,客户端说:"+info);
//返回客户端消息
pw.println("欢迎您!");
//
pw.flush();
if("end".equals(info)) {
break;
}
}
//socket.shutdownInput();//关闭输入流
//5、关闭资源
//pw.close();
//br.close();
socket.close();
serverSocket.close();
}
}
多对单服务器端
public class MultiClientServer {
private volatile static Map<String,Socket> socketes = new HashMap<>();
private static boolean isStop = false;
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(10086);
while (true) {
Socket client = server.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(
client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream(),true);
out.println("please input username!");
String name = in.readLine();
socketes.put(name, client);
SocketListener mc = new SocketListener(client);
new Thread(mc,name).start();
if(isStop) {
break;
}
}
server.close();
}
private static class SocketListener implements Runnable{
private Socket client;
private boolean isObjestStrean = false;
public SocketListener(Socket so) {
this.client = so;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
client.getInputStream()));
ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
PrintWriter out = new PrintWriter(client.getOutputStream());
//监听客户端输入
while (true) {
String str = "";
//对象流处理
if(isObjestStrean) {
Object o = ois.readObject();
MSG msg = null;
if(o instanceof MSG) {
msg = (MSG)o;
}else {
continue;
}
if(!msg.validate()) {
continue;
}
//处理消息
str = msg.getMsg();
PrintWriter out2 = new PrintWriter(socketes.get(msg.getReciever()).getOutputStream(),true);
out2.println(str);
}else {
//字符流
str = in.readLine();
System.out.println(str);
out.println("has receive....");
out.flush();
}
if (str.equals("end")) {
isStop = true;
break;
}
}
client.close();
} catch (IOException ex) {
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
}
}
}
public class MSG implements Serializable{
private static final long serialVersionUID = 1L;
private String sender;
private String msg;
private String reciever;
public String getSender() {
return sender;
}
public boolean validate() {
return socketes.containsKey(reciever)&&socketes.containsKey(sender);
}
public void setSender(String sender) {
this.sender = sender;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getReciever() {
return reciever;
}
public void setReciever(String reciever) {
this.reciever = reciever;
}
}
}