上一篇 java socket编程(2)——利用socket实现聊天之单聊
中我们讲到如何使用socket让客户端和客户端之间传递消息,实现一对一的聊天,接下来我将写出如何让服务器建立客户端与客户端之间的一对多通讯。
还是在原有的代码上加以修改,增加功能。
1,修改实体类(服务器端和客户端的实体类是一样的)
1,UserGroupBean 聊天群表
public class UserGroupBean implements Serializable {
private static final long serialVersionUID = 3L;
private int groupId;
private int userId;
private int groupNumberByMax;
private int groupNumberByCurrent;
private int groupType;
private int groupUserType;
}
2,MessageBean 消息表修改,增加聊天类型,是单聊还是群聊的标识
public class MessageBean implements Serializable {
private static final long serialVersionUID = 1L;
private long messageId;
private long groupId;
private int chatStyle;
private int chatType;
private String content;
private String errorMsg;
private int errorCode;
private int userId;
private int friendId;
private MessageFileBean chatFile;
}
3, UserInfoBean 用户信息表,加入该用户所拥有的群集合
public class UserInfoBean implements Serializable {
private static final long serialVersionUID = 2L;
private int userId;
private String userName;
private String likeName;
private String userPwd;
private String userIcon;
private List<UserGroupBean> groupList;
}
2,服务器增加逻辑
1,UserData 添加模拟数据
public class UserData {
/**
* 模拟数据库的用户信息,这里创建id不同的用户信息
*
* @param userId
* @return
*/
public static UserInfoBean getUserInfoBean(int userId) {
UserInfoBean userInfoBean = new UserInfoBean();
userInfoBean.setUserIcon("用户头像");
userInfoBean.setUserId(userId);
userInfoBean.setUserName("admin");
userInfoBean.setUserPwd("123123132a");
userInfoBean.setGroupList(getUserGroup());
return userInfoBean;
}
/**每个用户模拟两个群
* @return
*/
private static List<UserGroupBean> getUserGroup() {
List<UserGroupBean> list = new ArrayList<>();
for (int i = 1; i <= 2; i++) {
UserGroupBean userGroupBean = new UserGroupBean();
userGroupBean.setGroupId(i);
userGroupBean.setGroupNumberByMax(500);
userGroupBean.setGroupNumberByCurrent(20);
userGroupBean.setGroupType(i);
userGroupBean.setGroupUserType(-1);
list.add(userGroupBean);
}
return list;
}
}
- 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
- 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
2,ChatServer ,修改聊天服务的发送信息逻辑
public class ChatServer {
private static ServerSocket server;
public List<Socket> socketList = new ArrayList<>();
public Map<Integer, Socket> socketMap = new HashMap();
public Map<Integer, UserInfoBean> userMap = new HashMap();
public Gson gson = new Gson();
/**
* 初始化socket服务
*/
public void initServer() {
try {
server = new ServerSocket(SocketUrls.PORT);
createMessage();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 创建消息管理,一直接收消息
*/
private void createMessage() {
try {
System.out.println("等待用户接入 : ");
Socket socket = server.accept();
socketList.add(socket);
System.out.println("用户接入 : " + socket.getPort());
new Thread(new Runnable() {
public void run() {
createMessage();
}
}).start();
getMessage();
BufferedReader bff = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while (true) {
Thread.sleep(500);
while ((line = bff.readLine()) != null) {
MessageBean messageBean = gson.fromJson(line, MessageBean.class);
setChatMap(messageBean, socket);
getChatStyle(messageBean);
System.out.println("用户 : " + userMap.get(messageBean.getUserId()).getUserName());
System.out.println("内容 : " + messageBean.getContent());
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("错误 : " + e.getMessage());
}
}
/**
* 发送消息
*/
private void getMessage() {
new Thread(new Runnable() {
public void run() {
try {
String buffer;
while (true) {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
buffer = strin.readLine();
buffer += "\n";
for (Socket socket : socketMap.values()) {
OutputStream output = socket.getOutputStream();
output.write(buffer.getBytes("utf-8"));
output.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 模拟添加信息进入数据库和内存
*
* @param messageBean
* @param scoket
*/
private void setChatMap(MessageBean messageBean, Socket scoket) {
if (userMap != null && userMap.get(messageBean.getUserId()) == null) {
userMap.put(messageBean.getUserId(), UserData.getUserInfoBean(messageBean.getUserId()));
}
if (socketMap != null && socketMap.get(messageBean.getUserId()) == null) {
socketMap.put(messageBean.getUserId(), scoket);
}
}
/**
* 将消息转发给目标好友
*
* @param messageBean
*/
private void getChatStyle(MessageBean messageBean) {
switch (messageBean.getChatStyle()) {
case 0:
getFriendChat(messageBean);
break;
case 1:
getGroupChat(messageBean);
break;
case 3:
break;
case 4:
break;
}
}
/**
* 发送给好友的普通消息
*
* @param messageBean
*/
private void getFriendChat(MessageBean messageBean) {
if (messageBean.getContent().equals("[USER_LOGIN]"))
return;
if (socketMap != null && socketMap.get(messageBean.getFriendId()) != null) {
Socket socket = socketMap.get(messageBean.getFriendId());
String buffer = gson.toJson(messageBean);
buffer += "\n";
try {
OutputStream output = socket.getOutputStream();
output.write(buffer.getBytes("utf-8"));
output.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发送群聊消息
*
* @param messageBean
*/
private void getGroupChat(MessageBean messageBean) {
if (messageBean.getContent().equals("[USER_LOGIN]"))
return;
if (userMap == null)
return;
for (UserInfoBean userInfoBean : userMap.values()) {
for (UserGroupBean userGroupBean : userInfoBean.getGroupList()) {
if (userGroupBean.getGroupId() == messageBean.getGroupId()) {
if (socketMap != null && socketMap.get(userInfoBean.getUserId()) != null
&& userInfoBean.getUserId() != messageBean.getUserId()) {
Socket socket = socketMap.get(userInfoBean.getUserId());
String buffer = gson.toJson(messageBean);
buffer += "\n";
try {
OutputStream output = socket.getOutputStream();
output.write(buffer.getBytes("utf-8"));
output.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
}
- 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
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 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
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
3,客户端增加页面
1,增加选择是进入单聊还是进入群聊。xml布局
<?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="wrap_content"
android:background="@android:color/darker_gray"
android:orientation="vertical">
<LinearLayout
android:id="@+id/friend_ly"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:src="@drawable/ic_friend" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="5dp"
android:text="好友名:张三"
android:textColor="@android:color/black"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/group_ly"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:background="@android:color/white"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:src="@drawable/ic_chat" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="5dp"
android:text="群名:闲聊群"
android:textColor="@android:color/black"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
- 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
- 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
2,ChatListActivity 选择聊天类型的activigty
public class ChatListActivity extends AppCompatActivity implements View.OnClickListener {
private LinearLayout friend_ly, group_ly;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chatlist);
friend_ly = (LinearLayout) findViewById(R.id.friend_ly);
group_ly = (LinearLayout) findViewById(R.id.group_ly);
friend_ly.setOnClickListener(this);
group_ly.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.friend_ly:
Intent intent = new Intent(ChatListActivity.this, MainActivity.class);
startActivity(intent);
break;
case R.id.group_ly:
Intent intent1 = new Intent(ChatListActivity.this, GroupActivity.class);
startActivity(intent1);
break;
}
}
}
- 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
- 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
3,ChatServer 客户端的聊天服务修改
public class ChatServer {
private Socket socket;
private Handler handler;
private MessageBean messageBean;
private Gson gson = new Gson();
PrintWriter printWriter;
InputStream input;
OutputStream output;
DataOutputStream dataOutputStream;
private Handler handlers = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == -1) {
sendMessages("[USER_LOGIN]");
}
}
};
public ChatServer(int status) {
initMessage(status);
initChatServer();
}
/**
* 消息队列,用于传递消息
*
* @param handler
*/
public void setChatHandler(Handler handler) {
this.handler = handler;
}
private void initChatServer() {
receiveMessage();
}
/**
* 初始化用户信息
*/
private void initMessage(int status) {
messageBean = new MessageBean();
UserInfoBean userInfoBean = new UserInfoBean();
userInfoBean.setUserId(2);
messageBean.setMessageId(1);
messageBean.setChatType(1);
messageBean.setChatStyle(1);
userInfoBean.setUserName("admin");
userInfoBean.setUserPwd("123123123a");
if (status == 1) {
messageBean.setUserId(1);
messageBean.setFriendId(2);
} else if (status == 2) {
messageBean.setUserId(2);
messageBean.setFriendId(1);
} else if (status == 3) {
messageBean.setUserId(3);
messageBean.setFriendId(1);
}
messageBean.setGroupId(1);
ChatAppliaction.userInfoBean = userInfoBean;
}
/**
* 发送消息
*
* @param contentMsg
*/
public void sendMessages(String contentMsg) {
if (TextUtils.isEmpty(contentMsg)) return;
try {
if (socket == null) {
Message message = handler.obtainMessage();
message.what = 1;
message.obj = "服务器已经关闭";
handler.sendMessage(message);
return;
}
byte[] str = contentMsg.getBytes("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();
} catch (Exception e) {
e.printStackTrace();
Log.e("test", "错误:" + e.toString());
}
}
/**
* 接收消息,在子线程中
*/
private void receiveMessage() {
new Thread(new Runnable() {
@Override
public void run() {
try {
socket = new Socket(SocketUrls.IP, SocketUrls.PORT);
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;
Message messages = handlers.obtainMessage();
messages.what = -1;
handlers.sendMessage(messages);
while (true) {
Thread.sleep(500);
while ((line = bff.readLine()) != null) {
Log.i("socket", "内容 : " + line);
MessageBean messageBean = gson.fromJson(line, MessageBean.class);
Message message = handler.obtainMessage();
message.obj = messageBean;
message.what = 1;
handler.sendMessage(message);
}
if (socket == null)
break;
}
output.close();
input.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
Log.e("test", "错误:" + e.toString());
}
}
}).start();
}
public Socket getSocekt() {
if (socket == null) return null;
return socket;
}
}
- 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
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 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
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
所有的代码逻辑都修改完了,在原来一对一单聊的基础上修改成了一对多的群聊。
如果能够顺利的理解socket的消息推送,一对一聊天,那么一对多的聊天也不是什么难事。
附上demo供大家学习