配色: 字号:
Java Socket聊天室编程(二)之利用socket实现单聊聊天室
2016-10-11 | 阅:  转:  |  分享 
  
JavaSocket聊天室编程(二)之利用socket实现单聊聊天室



这篇文章主要介绍了JavaSocket聊天室编程(二)之利用socket实现单聊聊天室的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下



在上篇文章JavaSocket聊天室编程(一)之利用socket实现聊天之消息推送中我们讲到如何使用socket让服务器和客户端之间传递消息,达到推送消息的目的,接下来我将写出如何让服务器建立客户端与客户端之间的通讯。



其实就是建立一个一对一的聊天通讯。



与上一篇实现消息推送的代码有些不同,在它上面加以修改的。



如果没有提到的方法或者类则和上一篇一模一样。





1,修改实体类(服务器端和客户端的实体类是一样的)



1,UserInfoBean用户信息表





123456789



publicclassUserInfoBeanimplementsSerializable{privatestaticfinallongserialVersionUID=2L;privatelonguserId;//用户idprivateStringuserName;//用户名privateStringlikeName;//昵称privateStringuserPwd;//用户密码privateStringuserIcon;//用户头像//省略get、set方法}



2,MessageBean聊天信息表





1234567891011121314



publicclassMessageBeanimplementsSerializable{privatestaticfinallongserialVersionUID=1L;privatelongmessageId;//消息idprivatelonggroupId;//群idprivatebooleanisGoup;//是否是群消息privateintchatType;//消息类型;1,文本;2,图片;3,小视频;4,文件;5,地理位置;6,语音;7,视频通话privateStringcontent;//文本消息内容privateStringerrorMsg;//错误信息privateinterrorCode;//错误代码privateintuserId;//用户idprivateintfriendId;//目标好友idprivateMessageFileBeanchatFile;//消息附件//省略get、set方法}



3,MessageFileBean消息附件表





12345678910



publicclassMessageFileBeanimplementsSerializable{privatestaticfinallongserialVersionUID=3L;privateintfileId;//文件idprivateStringfileName;//文件名称privatelongfileLength;//文件长度privateByte[]fileByte;//文件内容privateStringfileType;//文件类型privateStringfileTitle;//文件头名称//省略get、set方法}



2,(服务器端代码修改)ChatServer主要的聊天服务类,加以修改





123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154



publicclassChatServer{//socket服务privatestaticServerSocketserver;//使用ArrayList存储所有的SocketpublicListsocketList=newArrayList<>();//模仿保存在内存中的socketpublicMapsocketMap=newHashMap();//模仿保存在数据库中的用户信息publicMapuserMap=newHashMap();publicGsongson=newGson();/初始化socket服务/publicvoidwww.visa158.cominitServer(){try{//创建一个ServerSocket在端口8080监听客户请求server=newServerSocket(SocketUrls.PORT);createMessage();}catch(IOExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}}/创建消息管理,一直接收消息/privatevoidcreateMessage(){try{System.out.println("等待用户接入:");//使用accept()阻塞等待客户请求Socketsocket=server.accept();//将链接进来的socket保存到集合中socketList.add(socket);System.out.println("用户接入:"+socket.getPort());//开启一个子线程来等待另外的socket加入newThread(newRunnable(){publicvoidrun(){//再次创建一个socket服务等待其他用户接入createMessage();}}).start();//用于服务器推送消息给用户getMessage();//从客户端获取信息BufferedReaderbff=newBufferedReader(newInputStreamReader(socket.getInputStream()));//读取发来服务器信息Stringline=null;//循环一直接收当前socket发来的消息while(true){Thread.sleep(500);//System.out.println("内容:"+bff.readLine());//获取客户端的信息while((line=bff.readLine())!=null){//解析实体类MessageBeanmessageBean=gson.fromJson(line,MessageBean.class);//将用户信息添加进入map中,模仿添加进数据库和内存//实体类存入数据库,socket存入内存中,都以用户id作为参照setChatMap(messageBean,socket);//将用户发送进来的消息转发给目标好友getFriend(messageBean);System.out.println("用户:"+userMap.get(messageBean.getUserId()).getUserName());System.out.println("内容:"+messageBean.getContent());}}//server.close();}catch(Exceptione){//TODOAuto-generatedcatchblocke.printStackTrace();System.out.println("错误:"+e.getMessage());}}/发送消息/privatevoidgetMessage(){newThread(newRunnable(){publicvoidrun(){try{Stringbuffer;while(true){//从控制台输入BufferedReaderstrin=newBufferedReader(newInputStreamReader(System.in));buffer=strin.readLine();//因为readLine以换行符为结束点所以,结尾加入换行buffer+="\n";//这里修改成向全部连接到服务器的用户推送消息for(Socketsocket:socketMap.values()){OutputStreamoutput=socket.getOutputStream();output.write(buffer.getBytes("utf-8"));//发送数据output.flush();}}}catch(IOExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}}}).start();}/模拟添加信息进入数据库和内存@parammessageBean@paramscoket/privatevoidsetChatMap(MessageBeanmessageBean,Socketscoket){//将用户信息存起来if(userMap!=null&&userMap.get(messageBean.getUserId())==null){userMap.put(messageBean.getUserId(),getUserInfoBean(messageBean.getUserId()));}//将对应的链接进来的socket存起来if(socketMap!=null&&socketMap.get(messageBean.getUserId())==null){socketMap.put(messageBean.getUserId(),scoket);}}/模拟数据库的用户信息,这里创建id不同的用户信息@paramuserId@return/privateUserInfoBeangetUserInfoBean(intuserId){UserInfoBeanuserInfoBean=newUserInfoBean();userInfoBean.setUserIcon("用户头像");userInfoBean.setUserId(userId);userInfoBean.setUserName("admin");userInfoBean.setUserPwd("123123132a");returnuserInfoBean;}/将消息转发给目标好友@parammessageBean/privatevoidgetFriend(MessageBeanmessageBean){if(socketMap!=null&&socketMap.get(messageBean.getFriendId())!=null){Socketsocket=socketMap.get(messageBean.getFriendId());Stringbuffer=gson.toJson(messageBean);//因为readLine以换行符为结束点所以,结尾加入换行buffer+="\n";try{//向客户端发送信息OutputStreamoutput=socket.getOutputStream();output.write(buffer.getBytes("utf-8"));//发送数据output.flush();}catch(IOExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}}}}



3,(客户端代码)LoginActivity登陆页面修改可以登录多人





1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253



publicclassLoginActivityextendsAppCompatActivity{privateEditTextchat_name_text,chat_pwd_text;privateButtonchat_login_btn;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.www.hunanwang.net.activity_login);chat_name_text=(EditText)findViewById(R.id.chat_name_text);chat_pwd_text=(EditText)findViewById(R.id.chat_pwd_text);chat_login_btn=(Button)findViewById(R.id.chat_login_btn);chat_login_btn.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){intstatus=getLogin(chat_name_text.getText().toString().trim(),chat_pwd_text.getText().toString().trim());if(status==-1||status==0){Toast.makeText(LoginActivity.this,"密码错误",Toast.LENGTH_LONG).show();return;}getChatServer(getLogin(chat_name_text.getText().toString().trim(),chat_pwd_text.getText().toString().trim()));Intentintent=newIntent(LoginActivity.this,MainActivity.class);startActivity(intent);finish();}});}/返回登陆状态,1为用户,2为另一个用户,这里模拟出两个用户互相通讯@paramname@parampwd@return/privateintgetLogin(Stringname,Stringpwd){if(TextUtils.isEmpty(name)||TextUtils.isEmpty(pwd)){return0;//没有输入完整密码}elseif(name.equals("admin")&&pwd.equals("1")){return1;//用户1}elseif(name.equals("admin")&&pwd.equals("2")){return2;//用户2}else{return-1;//密码错误}}/实例化一个聊天服务@paramstatus/privatevoidgetChatServer(intstatus){ChatAppliaction.chatServer=newChatServer(status);}}



4,(客户端代码)ChatServer聊天服务代码逻辑的修改





123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126



publicclassChatServer{privateSocketsocket;privateHandlerhandler;privateMessageBeanmessageBean;privateGsongson=newGson();//由Socket对象得到输出流,并构造PrintWriter对象PrintWriterprintWriter;InputStreaminput;OutputStreamoutput;DataOutputStreamdataOutputStream;publicChatServer(intstatus){initMessage(status);initChatServer();}/消息队列,用于传递消息@paramhandler/publicvoidsetChatHandler(Handlerhandler){this.handler=handler;}privatevoidinitChatServer(){//开个线程接收消息receiveMessage();}/初始化用户信息/privatevoidinitMessage(intstatus){messageBean=newMessageBean();UserInfoBeanuserInfoBean=newUserInfoBean();userInfoBean.setUserId(2);messageBean.setMessageId(1);messageBean.setChatType(1);userInfoBean.setUserName("admin");userInfoBean.setUserPwd("123123123a");//以下操作模仿当用户点击了某个好友展开的聊天界面,将保存用户id和聊天目标用户idif(status==1){//如果是用户1,那么他就指向用户2聊天messageBean.setUserId(1);messageBean.setFriendId(2);}elseif(status==2){//如果是用户2,那么他就指向用户1聊天messageBean.setUserId(2);messageBean.setFriendId(1);}ChatAppliaction.userInfoBean=userInfoBean;}/发送消息@paramcontentMsg/publicvoidsendMessage(StringcontentMsg){try{if(socket==null){Messagemessage=handler.obtainMessage();message.what=1;message.obj="服务器已经关闭";handler.sendMessage(message);return;}byte[]str=contentMsg.getBytes("utf-8");//将内容转utf-8Stringaaa=newString(str);messageBean.setContent(aaa);StringmessageJson=gson.toJson(messageBean);/因为服务器那边的readLine()为阻塞读取如果它读取不到换行符或者输出流结束就会一直阻塞在那里所以在json消息最后加上换行符,用于告诉服务器,消息已经发送完毕了/messageJson+="\n";output.write(messageJson.getBytes("utf-8"));//换行打印output.flush();//刷新输出流,使Server马上收到该字符串}catch(Exceptione){e.printStackTrace();Log.e("test","错误:"+e.toString());}}/接收消息,在子线程中/privatevoidreceiveMessage(){newThread(newRunnable(){@Overridepublicvoidrun(){try{//向本机的8080端口发出客户请求socket=newSocket(SocketUrls.IP,SocketUrls.PORT);//由Socket对象得到输入流,并构造相应的BufferedReader对象printWriter=newPrintWriter(socket.getOutputStream());input=socket.getInputStream();output=socket.getOutputStream();dataOutputStream=newDataOutputStream(socket.getOutputStream());//从客户端获取信息BufferedReaderbff=newBufferedReader(newInputStreamReader(input));//读取发来服务器信息Stringline;while(true){Thread.sleep(500);//获取客户端的信息while((line=bff.readLine())!=null){Log.i("socket","内容:"+line);MessageBeanmessageBean=gson.fromJson(line,MessageBean.class);Messagemessage=handler.obtainMessage();message.obj=messageBean.getContent();message.what=1;handler.sendMessage(message);}if(socket==null)break;}output.close();//关闭Socket输出流input.close();//关闭Socket输入流socket.close();//关闭Socket}catch(Exceptione){e.printStackTrace();Log.e("test","错误:"+e.toString());}}}).start();}publicSocketgetSocekt(){if(socket==null)returnnull;returnsocket;}}



如此一来,代码逻辑已经从消息推送的逻辑修改成了单聊的逻辑了。



这个代码可以让用户1和用户2相互聊天,并且服务器会记录下他们之间的聊天记录。并且服务器还是拥有消息推送的功能。



以上所述是小编给大家介绍的JavaSocket聊天室编程(二)之利用socket实现单聊聊天室,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!























献花(0)
+1
(本文系白狐一梦首藏)