通信(服务器客户端的群聊与网络画板)

进入了通信阶段,感觉和之前学的内容差异很大,对这方面也没有之前那么感兴趣……有点缺乏热情进

度上不来……同时还在改进之前的线程游戏,很久没更新了。做了可以连接多个客户端,群发消息的服务

器,和可以同步画图的画板,一起总结一下。

1.思路:
需要实现的功能:
服务器:
1.创建一个连接
2.被客户端连接,将线程加入一个队列中。
3.打开客户端的输入输出流
4.将消息写入客户端的输出流
5.群发,遍历整个队列,将数据写入每个客户端的输出流。
6.读入客户端写入自身输出流的内容,再按照协议表达。

客户端:
1.连接服务器
2.打开服务器的输入输出流
3.读取服务器写入自身输入流的数据,按照协议表达。
4.把需要传递的内容写入服务器的输入流中,再由服务器调用群发方法,实现客户端与客户端之间的交流

感觉通信和之前学习的内容有个很大的区别,就是程序的每个部分都是紧密关联的,环环相扣,哪一个部

分出了问题都出不了效果。需要在思绪清晰的时候写。之前几天原理不太明确走了很多弯路。

服务器和客户端的写法都可以简化为几步:

服务器:
1.创建服务器
2.进入等待状态 accept
3.获取输入输出流

客户端:
1.new socket
2.获取输入输出流


其他功能的实现,只需定义不同的协议,就能实现。

2.服务器和客户端一起所需要的类比较多,一开始写因为类名规定不合理给自己添加了许多麻烦。这里稍

微提一下:
服务器:
服务器界面类:ServerUI;
服务器创建线程:CreatServer
服务器读写线程:ServerThread
服务器群发类:ChatConnect

客户端:
客户端界面:ClientUI
客户端读写线程:ClientThread

还有各种监听器,和辅助类,那就根据需求来。
姑且服务器相关的都以Server打头,客户端的都以Client打头好了。

 

服务器界面1:



 

客户端界面1:




 
 

 

3.新涉及的类
1.类 Socket

public class Socketextends Object此类实现客户端套接字(也可以就叫“套接字”)。套接字是两

台机器间通信的端点。

套接字的实际工作由 SocketImpl 类的实例执行。应用程序通过更改创建套接字实现的套接字工厂可以

配置它自身,以创建适合本地防火墙的套接字。

涉及的用法:
while(true){
//阻塞
Socket client=s.accept();
System.out.println("进入连接:"+client.getRemoteSocketAddress());
方法:
getRemoteSocketAddress()
返回此套接字连接的端点的地址,如果未连接则返回 null。


2.类 ServerSocket
此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向

请求者返回结果。

服务器套接字的实际工作由 SocketImpl 类的实例执行。应用程序可以更改创建套接字实现的套接字工

厂来配置它自身,从而创建适合本地防火墙的套接字。

涉及的用法:
java.net.ServerSocket s=new java.net.ServerSocket(this.port);
System.out.println("服务器创建成功!"+port);

方法:
accept()
侦听并接受到此套接字的连接。

3.telnet
在最开始调试服务器时,使用了一个WINDOWS自带的简易客户端,telnet。
连接服务器的格式:
telnet IP 端口号。
另外在CMD中使用指令:ipconfig 可以获取主机的IP地址

3.在网络画板部分实现的功能:
1.切换画笔类型(划线画圆画方框)
2.多客户端连接服务器
3.群画群聊

 

服务器界面2:



  

客户端界面2:



 

源代码:

 

创建线程:

import java.awt.Graphics;
import java.net.Socket;

import javax.swing.JTextArea;

public class creatThread extends Thread{
 private int port;
 private int count;
 private Graphics g;
 private JTextArea JA;
 public chatThread ct;
 
 public creatThread(int port,JTextArea JA,int count,Graphics g){
  this.port=port;
  this.JA=JA;
  this.count=count;
  this.count++;
  this.g=g;
 }  
 
 public void run(){
  creatchat();
 }
 
 
 private void creatchat() {
     try{
      java.net.ServerSocket s=new java.net.ServerSocket(this.port);
    System.out.println("服务器创建成功!"+port);
    //让服务器进入循环等待状态
    while(true){
     //阻塞
     Socket client=s.accept();
     System.out.println("进入连接:"+client.getRemoteSocketAddress());
     //创建线程
     ct=new chatThread(client,JA,g);
     this.setchatThread(ct); 
     //保存至队列
     Chatconnect.add(ct);
     ct.start();
//    
     }

     }catch(Exception ef){
    ef.printStackTrace();
   }
 }
 public void  setchatThread(chatThread ct){
  this.ct = ct;
 }
 public chatThread getchatThread(){
  return this.ct;
 }
}

 

 

服务器线程:

public class chatThread extends Thread{
	
	private Socket client;
	private  OutputStream ous;
	private  InputStream ins;
	private JTextArea JA;
	int count;
	static Graphics g;
	DataInputStream dins;
	DataOutputStream dous;
	ServerMouse sm;
	public chatThread(Socket client,JTextArea JA,Graphics g){
		this.client=client;
		this.JA=JA;
		this.g=g;
		
	}
	
	public void run(){
	
		processChat();
		
	}
	public  void processChat() {
		 try{  
			 
			   //从通话对象上获取输入输出流
			   ins=this.client.getInputStream();
			   ous=this.client.getOutputStream();
			   dins=new DataInputStream(ins);
			   dous=new DataOutputStream(ous);
			    
			  } catch(Exception ef){
					ef.printStackTrace();
			  }
			  //服务器读入客户端发来的数据
			  while(true){
			  try {
//				  String msg=("welcom!\r\n");
//				   byte[] bb=msg.getBytes();
//				   ous.write(bb);
				   
					byte b = dins.readByte();
					 System.out.println("服务器读入,type="+b);
						if(b==1){
							int x1 = dins.readInt();
							int y1 = dins.readInt();
							int x2 = dins.readInt();
							int y2 = dins.readInt();
							System.out.println("画线  "+"x1="+x1+",y1="+y1+",x2="+x2+",y2="+y2);
							g.drawLine(x1, y1, x2, y2);
							Chatconnect.sendmsg(1,x1,y1,x2,y2);
						}
						if(b==2){
							int x1 = dins.readInt();
							int y1 = dins.readInt();
							int x2 = dins.readInt();
							int y2 = dins.readInt();
							System.out.println("画圆  "+"x1="+x1+",y1="+y1+",x2="+x2+",y2="+y2);
							g.drawOval(x1, y1,Math.abs(x1-x2), Math.abs(y1-y2));
							Chatconnect.sendmsg(2,x1,y1,x2,y2);
						}
						if(b==3){
							int x1 = dins.readInt();
							int y1 = dins.readInt();
							int x2 = dins.readInt();
							int y2 = dins.readInt();
							System.out.println("画方框  "+"x1="+x1+",y1="+y1+",x2="+x2+",y2="+y2);
							g.drawRect(x1, y1,Math.abs(x1-x2), Math.abs(y1-y2));
							Chatconnect.sendmsg(3,x1,y1,x2,y2);
						}
//						//发送消息
//						if(b==4){
//							System.out.println("服务器发送消息");
//							 String s=readString(ins);
//							 this.JA.append("客户端"+count+":"+s+"\r\n");
//							   System.out.println("服务器写入运行!");
//							   System.out.println("user: "+s);
//							   Chatconnect.sendmsg(s);
//							   msg="host:"+s+"\r\n";
//							   bb=msg.getBytes();
							   ous.write(b);
//							   s=readString(ins);
//						}
					} catch (Exception e) {
						e.printStackTrace();
					}
			  }
	}
	
//	public static void writeLine(int x1,int y1,int x2,int y2){
//		try{ 
//		 dous.writeInt(1);
//	     dous.writeInt(x1);
//	     dous.writeInt(y1);
//	     dous.writeInt(x2);
//	     dous.writeInt(y2);
//	     }catch(Exception ef){
//				ef.printStackTrace();
//			}
//	}
//	
//	//字符读入
//	private String readString(InputStream ins) {
//		try{
//			   StringBuffer sb=new StringBuffer();
//			   int t=ins.read();
//			   while(t!='#'){
//				   sb.append((char)t);
//				   t=ins.read();
//			   }
//			   String s=sb.toString();
//			   return s;
//			  }catch(Exception ef){
//				  ef.printStackTrace();
//			  }
//			  return "error";
//		   }
//
//	public void sendmsg(String msg) {
//		try{
//			ous.write(4);
//			msg+="#";
//			ous.write(msg.getBytes());
//			}catch(Exception ef){
//				ef.printStackTrace();
//			}
//		
//	}
	public void sendmsg(int type,int x1,int y1,int x2,int y2) {
		try {
			System.out.println("服务器输出,TYPE="+type);
		if(type==1){
		
		//画线
		dous.writeByte(1);
		dous.writeInt(x1);
		dous.writeInt(y1);
		dous.writeInt(x2);
		dous.writeInt(y2);
		}
		if(type==2){
		
		//画圆
		dous.writeByte(2);
		dous.writeInt(x1);
		dous.writeInt(y1);
		dous.writeInt(x2);
		dous.writeInt(y2);
		}
		if(type==3){
			
		//画方框
		dous.writeByte(3);
		dous.writeInt(x1);
		dous.writeInt(y1);
		dous.writeInt(x2);
		dous.writeInt(y2);
		}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
		
	

}

 

 

4.调试心得


关于参数的传输:这里加入了鼠标监听器,当初在传送数据的时候纠结了一下。最后使用的方法是在监听

器里画好图后,然
后再调用线程中的方法,传入线程中,写入输出流中。

关于群发的实现思路:在实现客户端之间的交流时,思路上也走了弯路。虽然想法比较奇特,但是应该也

能实现,不知道为什么出了错误。最后换成了更加正常的思路:在监听器里画完图后,调用线程中的方法

写入服务器的输出流中。服务器的输入流获取信息之后,立即调用群发方法。

关于不同类型数据的传输:这里就关于协议了。一般的方式是定一个方式,先输出一个类型码,代表数据

类型,读取时再通过数据类型辨别,分别处理。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值