相关阅读:Java Socket聊天室编程(二)之利用socket实现单聊聊天室
网上已经有很多利用socket实现聊天的例子了,但是我看过很多,多多少有一些问题存在。
这里我将实现一个比较完整的聊天例子,并解释其中的逻辑。
由于socket这一块比较大,所以我将分出几篇来写一个比较完整的socket例子。
这里我们先来实现一个最简单的,服务器与客户端通讯,实现消息推送的功能。
目的:服务器与客户端建立连接,客户端可以向服务器发送消息,服务器可以向客户端推送消息。
1,使用java建立socket聊天服务器
1,SocketUrls 确定ip地址和端口号
1
2
3
4
5
6
|
public class SocketUrls{
// ip地址
public final static String IP = "192.168.1.110" ;
// 端口号
public final static int PORT = 8888 ;
}
|
2,Main 程序的入口
1
2
3
4
5
|
public class Main {
public static void main(String[] args) throws Exception {
new ChatServer().initServer();
}
}
|
3,Bean 实体类
用户信息 UserInfoBean
1
2
3
4
5
6
|
public class Main {
public static void main(String[] args) throws Exception {
new ChatServer().initServer();
}
}
|
聊天信息 MessageBean
1
2
3
4
5
6
7
8
9
10
|
public class MessageBean extends UserInfoBean {
private long messageId; // 消息id
private long groupId; // 群id
private boolean isGoup; // 是否是群消息
private String content; // 文本消息内容
private String errorMsg; // 错误信息
private int errorCode; // 错误代码
//省略get/set方法
}
|
4,ChatServer 聊天服务,最主要的程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
public class ChatServer {
// socket服务
private static ServerSocket server;
public Gson gson = new Gson();
/**
* 初始化socket服务
*/
public void initServer() {
try {
// 创建一个ServerSocket在端口8080监听客户请求
server = new ServerSocket(SocketUrls.PORT);
createMessage();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 创建消息管理,一直接收消息
*/
private void createMessage() {
try {
System.out.println( "等待用户接入 : " );
// 使用accept()阻塞等待客户请求
Socket socket = server.accept();
System.out.println( "用户接入 : " + socket.getPort());
// 开启一个子线程来等待另外的socket加入
new Thread( new Runnable() {
public void run() {
createMessage();
}
}).start();
// 向客户端发送信息
OutputStream output = socket.getOutputStream();
// 从客户端获取信息
BufferedReader bff = new BufferedReader( new InputStreamReader(socket.getInputStream()));
// Scanner scanner = new Scanner(socket.getInputStream());
new Thread( new Runnable() {
public void run() {
try {
String buffer;
while ( true ) {
// 从控制台输入
BufferedReader strin = new BufferedReader( new InputStreamReader(System.in));
buffer = strin.readLine();
// 因为readLine以换行符为结束点所以,结尾加入换行
buffer += "\n" ;
output.write(buffer.getBytes( "utf-8" ));
// 发送数据
output.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
// 读取发来服务器信息
String line = null ;
// 循环一直接收当前socket发来的消息
while ( true ) {
Thread.sleep( 500 );
// System.out.println("内容 : " + bff.readLine());
// 获取客户端的信息
while ((line = bff.readLine()) != null ) {
MessageBean messageBean = gson.fromJson(line, MessageBean. class );
System.out.println( "用户 : " + messageBean.getUserName());
System.out.println( "内容 : " + messageBean.getContent());
}
}
// server.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println( "错误 : " + e.getMessage());
}
}
}
|
2,Android 端作为移动端连接服务器
1,appliaction 实例化一个全局的聊天服务
1
2
3
4
5
6
7
8
|
public class ChatAppliaction extends Application {
public static ChatServer chatServer;
public static UserInfoBean userInfoBean;
@Override
public void onCreate() {
super .onCreate();
}
}
|
2,ip地址和端口号和服务器保持一致
3,聊天实力类同服务器端一样
4,xml布局。登陆,聊天
1,登录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<?xml version= "1.0" encoding= "utf-8" ?>
<LinearLayout xmlns: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,聊天
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
<?xml version= "1.0" encoding= "utf-8" ?>
<LinearLayout xmlns: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 登陆
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class LoginActivity extends AppCompatActivity {
private EditText chat_name_text, chat_pwd_text;
private Button chat_login_btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
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( new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getLogin(chat_name_text.getText().toString().trim(), chat_pwd_text.getText().toString().trim())) {
getChatServer();
Intent intent = new Intent(LoginActivity. this , MainActivity. class );
startActivity(intent);
finish();
}
}
});
}
private boolean getLogin(String name, String pwd) {
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)) return false ;
if (name.equals( "admin" ) && pwd.equals( "123123123a" )) return true ;
return false ;
}
private void getChatServer() {
ChatAppliaction.chatServer = new ChatServer();
}
}
|
6,MainActivity 聊天
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
public class MainActivity extends AppCompatActivity {
private LinearLayout chat_ly;
private TextView left_text, right_view;
private EditText chat_et;
private Button send_btn;
private ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@Override
protected void onCreate(Bundle savedInstanceState) {
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( new View.OnClickListener() {
@Override
public void onClick(View v) {
ChatAppliaction.chatServer.sendMessage(chat_et.getText().toString().trim());
chat_ly.addView(initRightView(chat_et.getText().toString().trim()));
}
});
//添加消息接收队列
ChatAppliaction.chatServer.setChatHandler( new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1 ) {
//发送回来消息后,更新ui
chat_ly.addView(initLeftView(msg.obj.toString()));
}
}
});
}
/**靠右的消息
* @param messageContent
* @return
*/
private View initRightView(String messageContent) {
right_view = new TextView( this );
right_view.setLayoutParams(layoutParams);
right_view.setGravity(View.FOCUS_RIGHT);
right_view.setText(messageContent);
return right_view;
}
/**靠左的消息
* @param messageContent
* @return
*/
private View initLeftView(String messageContent) {
left_text = new TextView( this );
left_text.setLayoutParams(layoutParams);
left_text.setGravity(View.FOCUS_LEFT);
left_text.setText(messageContent);
return left_text;
}
}
|
7,ChatServer 聊天逻辑,最主要的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
public class ChatServer {
private Socket socket;
private Handler handler;
private MessageBean messageBean;
private Gson gson = new Gson();
// 由Socket对象得到输出流,并构造PrintWriter对象
PrintWriter printWriter;
InputStream input;
OutputStream output;
DataOutputStream dataOutputStream;
public ChatServer() {
initMessage();
initChatServer();
}
/**
* 消息队列,用于传递消息
*
* @param handler
*/
public void setChatHandler(Handler handler) {
this .handler = handler;
}
private void initChatServer() {
//开个线程接收消息
receiveMessage();
}
/**
* 初始化用户信息
*/
private void initMessage() {
messageBean = new MessageBean();
messageBean.setUserId( 1 );
messageBean.setMessageId( 1 );
messageBean.setChatType( 1 );
messageBean.setUserName( "admin" );
ChatAppliaction.userInfoBean = messageBean;
}
/**
* 发送消息
*
* @param contentMsg
*/
public void sendMessage(String contentMsg) {
try {
if (socket == null ) {
Message message = handler.obtainMessage();
message.what = 1 ;
message.obj = "服务器已经关闭" ;
handler.sendMessage(message);
return ;
}
byte [] str = contentMsg.getBytes( "utf-8" ); //将内容转utf-8
String aaa = new String(str);
messageBean.setContent(aaa);
String messageJson = gson.toJson(messageBean);
/**
* 因为服务器那边的readLine()为阻塞读取
* 如果它读取不到换行符或者输出流结束就会一直阻塞在那里
* 所以在json消息最后加上换行符,用于告诉服务器,消息已经发送完毕了
* */
messageJson += "\n" ;
output.write(messageJson.getBytes( "utf-8" )); // 换行打印
output.flush(); // 刷新输出流,使Server马上收到该字符串
} catch (Exception e) {
e.printStackTrace();
Log.e( "test" , "错误:" + e.toString());
}
}
/**
* 接收消息,在子线程中
*/
private void receiveMessage() {
new Thread( new Runnable() {
@Override
public void run() {
try {
// 向本机的8080端口发出客户请求
socket = new Socket(SocketUrls.IP, SocketUrls.PORT);
// 由Socket对象得到输入流,并构造相应的BufferedReader对象
printWriter = new PrintWriter(socket.getOutputStream());
input = socket.getInputStream();
output = socket.getOutputStream();
dataOutputStream = new DataOutputStream(socket.getOutputStream());
// 从客户端获取信息
BufferedReader bff = new BufferedReader( new InputStreamReader(input));
// 读取发来服务器信息
String line;
while ( true ) {
Thread.sleep( 500 );
// 获取客户端的信息
while ((line = bff.readLine()) != null ) {
Log.i( "socket" , "内容 : " + line);
Message message = 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 (Exception e) {
e.printStackTrace();
Log.e( "test" , "错误:" + e.toString());
}
}
}).start();
}
}
|
写到这里,已经完成了所有的代码。
这个demo可以实现手机端向服务器发送消息,服务器向手机端发送消息。
这个demo可以算是推送功能,不过真正的推送没有这么简单。作为一个socket的入门了解,可以从中看到socket编程的思想。
以上所述是小编给大家介绍的Java Socket聊天室编程(一)之利用socket实现聊天之消息推送,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!
原文链接:http://blog.csdn.net/yehui928186846/article/details/52572157