Java Socket聊天室编程(一)之利用socket实现聊天之消息推送
相关阅读:JavaSocket聊天室编程(二)之利用socket实现单聊聊天室
网上已经有很多利用socket实现聊天的例子了,但是我看过很多,多多少有一些问题存在。
这里我将实现一个比较完整的聊天例子,并解释其中的逻辑。
由于socket这一块比较大,所以我将分出几篇来写一个比较完整的socket例子。
这里我们先来实现一个最简单的,服务器与客户端通讯,实现消息推送的功能。
目的:服务器与客户端建立连接,客户端可以向服务器发送消息,服务器可以向客户端推送消息。
1,使用java建立socket聊天服务器
1,SocketUrls确定ip地址和端口号
publicclassSocketUrls{ //ip地址 publicfinalstaticStringIP="192.168.1.110"; //端口号 publicfinalstaticintPORT=8888; }
2,Main程序的入口
publicclassMain{ publicstaticvoidmain(String[]args)throwsException{ newChatServer().initServer(); } }
3,Bean实体类
用户信息UserInfoBean
publicclassMain{ publicstaticvoidmain(String[]args)throwsException{ newChatServer().initServer(); } }
聊天信息MessageBean
publicclassMessageBeanextendsUserInfoBean{ privatelongmessageId;//消息id privatelonggroupId;//群id privatebooleanisGoup;//是否是群消息 privateintchatType;//消息类型;1,文本;2,图片;3,小视频;4,文件;5,地理位置;6,语音;7,视频通话 privateStringcontent;//文本消息内容 privateStringerrorMsg;//错误信息 privateinterrorCode;//错误代码 //省略get/set方法 }
4,ChatServer聊天服务,最主要的程序
publicclassChatServer{ //socket服务 privatestaticServerSocketserver; publicGsongson=newGson(); /** *初始化socket服务 */ publicvoidinitServer(){ try{ //创建一个ServerSocket在端口8080监听客户请求 server=newServerSocket(SocketUrls.PORT); createMessage(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } /** *创建消息管理,一直接收消息 */ privatevoidcreateMessage(){ try{ System.out.println("等待用户接入:"); //使用accept()阻塞等待客户请求 Socketsocket=server.accept(); System.out.println("用户接入:"+socket.getPort()); //开启一个子线程来等待另外的socket加入 newThread(newRunnable(){ publicvoidrun(){ createMessage(); } }).start(); //向客户端发送信息 OutputStreamoutput=socket.getOutputStream(); //从客户端获取信息 BufferedReaderbff=newBufferedReader(newInputStreamReader(socket.getInputStream())); //Scannerscanner=newScanner(socket.getInputStream()); newThread(newRunnable(){ publicvoidrun(){ try{ Stringbuffer; while(true){ //从控制台输入 BufferedReaderstrin=newBufferedReader(newInputStreamReader(System.in)); buffer=strin.readLine(); //因为readLine以换行符为结束点所以,结尾加入换行 buffer+="\n"; output.write(buffer.getBytes("utf-8")); //发送数据 output.flush(); } }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } }).start(); //读取发来服务器信息 Stringline=null; //循环一直接收当前socket发来的消息 while(true){ Thread.sleep(500); //System.out.println("内容:"+bff.readLine()); //获取客户端的信息 while((line=bff.readLine())!=null){ MessageBeanmessageBean=gson.fromJson(line,MessageBean.class); System.out.println("用户:"+messageBean.getUserName()); System.out.println("内容:"+messageBean.getContent()); } } //server.close(); }catch(Exceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); System.out.println("错误:"+e.getMessage()); } } }
2,Android端作为移动端连接服务器
1,appliaction实例化一个全局的聊天服务
publicclassChatAppliactionextendsApplication{ publicstaticChatServerchatServer; publicstaticUserInfoBeanuserInfoBean; @Override publicvoidonCreate(){ super.onCreate(); } }
2,ip地址和端口号和服务器保持一致
3,聊天实力类同服务器端一样
4,xml布局。登陆,聊天
1,登录
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <EditText android:id="@+id/chat_name_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="用户名" android:text="admin"/> <EditText android:id="@+id/chat_pwd_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="密码" android:text="123123123a" android:inputType="numberPassword"/> <Button android:id="@+id/chat_login_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="登录"/> </LinearLayout>
2,聊天
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".activity.MainActivity"> <ScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="0.9"> <LinearLayout android:id="@+id/chat_ly" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> </LinearLayout> </ScrollView> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <EditText android:id="@+id/chat_et" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="0.8"/> <Button android:id="@+id/send_btn" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="0.2" android:text="发送"/> </LinearLayout> </LinearLayout>
5,LoginActivity登陆
publicclassLoginActivityextendsAppCompatActivity{ privateEditTextchat_name_text,chat_pwd_text; privateButtonchat_login_btn; @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.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(){ @Override publicvoidonClick(Viewv){ if(getLogin(chat_name_text.getText().toString().trim(),chat_pwd_text.getText().toString().trim())){ getChatServer(); Intentintent=newIntent(LoginActivity.this,MainActivity.class); startActivity(intent); finish(); } } }); } privatebooleangetLogin(Stringname,Stringpwd){ if(TextUtils.isEmpty(name)||TextUtils.isEmpty(pwd))returnfalse; if(name.equals("admin")&&pwd.equals("123123123a"))returntrue; returnfalse; } privatevoidgetChatServer(){ ChatAppliaction.chatServer=newChatServer(); } }
6,MainActivity聊天
publicclassMainActivityextendsAppCompatActivity{ privateLinearLayoutchat_ly; privateTextViewleft_text,right_view; privateEditTextchat_et; privateButtonsend_btn; privateViewGroup.LayoutParamslayoutParams=newViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT); @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); chat_ly=(LinearLayout)findViewById(R.id.chat_ly); chat_et=(EditText)findViewById(R.id.chat_et); send_btn=(Button)findViewById(R.id.send_btn); send_btn.setOnClickListener(newView.OnClickListener(){ @Override publicvoidonClick(Viewv){ ChatAppliaction.chatServer.sendMessage(chat_et.getText().toString().trim()); chat_ly.addView(initRightView(chat_et.getText().toString().trim())); } }); //添加消息接收队列 ChatAppliaction.chatServer.setChatHandler(newHandler(){ @Override publicvoidhandleMessage(Messagemsg){ if(msg.what==1){ //发送回来消息后,更新ui chat_ly.addView(initLeftView(msg.obj.toString())); } } }); } /**靠右的消息 *@parammessageContent *@return */ privateViewinitRightView(StringmessageContent){ right_view=newTextView(this); right_view.setLayoutParams(layoutParams); right_view.setGravity(View.FOCUS_RIGHT); right_view.setText(messageContent); returnright_view; } /**靠左的消息 *@parammessageContent *@return */ privateViewinitLeftView(StringmessageContent){ left_text=newTextView(this); left_text.setLayoutParams(layoutParams); left_text.setGravity(View.FOCUS_LEFT); left_text.setText(messageContent); returnleft_text; } }
7,ChatServer聊天逻辑,最主要的
publicclassChatServer{ privateSocketsocket; privateHandlerhandler; privateMessageBeanmessageBean; privateGsongson=newGson(); //由Socket对象得到输出流,并构造PrintWriter对象 PrintWriterprintWriter; InputStreaminput; OutputStreamoutput; DataOutputStreamdataOutputStream; publicChatServer(){ initMessage(); initChatServer(); } /** *消息队列,用于传递消息 * *@paramhandler */ publicvoidsetChatHandler(Handlerhandler){ this.handler=handler; } privatevoidinitChatServer(){ //开个线程接收消息 receiveMessage(); } /** *初始化用户信息 */ privatevoidinitMessage(){ messageBean=newMessageBean(); messageBean.setUserId(1); messageBean.setMessageId(1); messageBean.setChatType(1); messageBean.setUserName("admin"); ChatAppliaction.userInfoBean=messageBean; } /** *发送消息 * *@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-8 Stringaaa=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(){ @Override publicvoidrun(){ 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); Messagemessage=handler.obtainMessage(); message.obj=line; 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(); } }
写到这里,已经完成了所有的代码。
这个demo可以实现手机端向服务器发送消息,服务器向手机端发送消息。
这个demo可以算是推送功能,不过真正的推送没有这么简单。作为一个socket的入门了解,可以从中看到socket编程的思想。
以上所述是小编给大家介绍的JavaSocket聊天室编程(一)之利用socket实现聊天之消息推送,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!