欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java Socket聊天室編程(二)之利用socket實(shí)現(xiàn)單聊聊天室

 更新時(shí)間:2016年09月19日 11:28:20   作者:夜輝疾風(fēng)  
這篇文章主要介紹了Java Socket聊天室編程(二)之利用socket實(shí)現(xiàn)單聊聊天室的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下

在上篇文章Java Socket聊天室編程(一)之利用socket實(shí)現(xiàn)聊天之消息推送中我們講到如何使用socket讓服務(wù)器和客戶(hù)端之間傳遞消息,達(dá)到推送消息的目的,接下來(lái)我將寫(xiě)出如何讓服務(wù)器建立客戶(hù)端與客戶(hù)端之間的通訊。

其實(shí)就是建立一個(gè)一對(duì)一的聊天通訊。

與上一篇實(shí)現(xiàn)消息推送的代碼有些不同,在它上面加以修改的。

如果沒(méi)有提到的方法或者類(lèi)則和上一篇一模一樣。

1,修改實(shí)體類(lèi)(服務(wù)器端和客戶(hù)端的實(shí)體類(lèi)是一樣的)

1,UserInfoBean 用戶(hù)信息表

public class UserInfoBean implements Serializable {
private static final long serialVersionUID = 2L;
private long userId;// 用戶(hù)id
private String userName;// 用戶(hù)名
private String likeName;// 昵稱(chēng)
private String userPwd;// 用戶(hù)密碼
private String userIcon;// 用戶(hù)頭像
//省略get、set方法
}

2,MessageBean 聊天信息表

public class MessageBean implements Serializable {
private static final long serialVersionUID = 1L;
private long messageId;// 消息id
private long groupId;// 群id
private boolean isGoup;// 是否是群消息
private int chatType;// 消息類(lèi)型;1,文本;2,圖片;3,小視頻;4,文件;5,地理位置;6,語(yǔ)音;7,視頻通話
private String content;// 文本消息內(nèi)容
private String errorMsg;// 錯(cuò)誤信息
private int errorCode;// 錯(cuò)誤代碼
private int userId;//用戶(hù)id
private int friendId;//目標(biāo)好友id
private MessageFileBean chatFile;// 消息附件
//省略get、set方法
}

3,MessageFileBean 消息附件表

public class MessageFileBean implements Serializable {
private static final long serialVersionUID = 3L;
private int fileId;//文件id
private String fileName;//文件名稱(chēng)
private long fileLength;//文件長(zhǎng)度
private Byte[] fileByte;//文件內(nèi)容
private String fileType;//文件類(lèi)型
private String fileTitle;//文件頭名稱(chēng)
//省略get、set方法
}

2,(服務(wù)器端代碼修改)ChatServer 主要的聊天服務(wù)類(lèi),加以修改

public class ChatServer {
// socket服務(wù)
private static ServerSocket server;
// 使用ArrayList存儲(chǔ)所有的Socket
public List<Socket> socketList = new ArrayList<>();
// 模仿保存在內(nèi)存中的socket
public Map<Integer, Socket> socketMap = new HashMap();
// 模仿保存在數(shù)據(jù)庫(kù)中的用戶(hù)信息
public Map<Integer, UserInfoBean> userMap = new HashMap();
public Gson gson = new Gson();
/**
* 初始化socket服務(wù)
*/
public void initServer() {
try {
// 創(chuàng)建一個(gè)ServerSocket在端口8080監(jiān)聽(tīng)客戶(hù)請(qǐng)求
server = new ServerSocket(SocketUrls.PORT);
createMessage();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 創(chuàng)建消息管理,一直接收消息
*/
private void createMessage() {
try {
System.out.println("等待用戶(hù)接入 : ");
// 使用accept()阻塞等待客戶(hù)請(qǐng)求
Socket socket = server.accept();
// 將鏈接進(jìn)來(lái)的socket保存到集合中
socketList.add(socket);
System.out.println("用戶(hù)接入 : " + socket.getPort());
// 開(kāi)啟一個(gè)子線程來(lái)等待另外的socket加入
new Thread(new Runnable() {
public void run() {
// 再次創(chuàng)建一個(gè)socket服務(wù)等待其他用戶(hù)接入
createMessage();
}
}).start();
// 用于服務(wù)器推送消息給用戶(hù)
getMessage();
// 從客戶(hù)端獲取信息
BufferedReader bff = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 讀取發(fā)來(lái)服務(wù)器信息
String line = null;
// 循環(huán)一直接收當(dāng)前socket發(fā)來(lái)的消息
while (true) {
Thread.sleep(500);
// System.out.println("內(nèi)容 : " + bff.readLine());
// 獲取客戶(hù)端的信息
while ((line = bff.readLine()) != null) {
// 解析實(shí)體類(lèi)
MessageBean messageBean = gson.fromJson(line, MessageBean.class);
// 將用戶(hù)信息添加進(jìn)入map中,模仿添加進(jìn)數(shù)據(jù)庫(kù)和內(nèi)存
// 實(shí)體類(lèi)存入數(shù)據(jù)庫(kù),socket存入內(nèi)存中,都以用戶(hù)id作為參照
setChatMap(messageBean, socket);
// 將用戶(hù)發(fā)送進(jìn)來(lái)的消息轉(zhuǎn)發(fā)給目標(biāo)好友
getFriend(messageBean);
System.out.println("用戶(hù) : " + userMap.get(messageBean.getUserId()).getUserName());
System.out.println("內(nèi)容 : " + messageBean.getContent());
}
}
// server.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("錯(cuò)誤 : " + e.getMessage());
}
}
/**
* 發(fā)送消息
*/
private void getMessage() {
new Thread(new Runnable() {
public void run() {
try {
String buffer;
while (true) {
// 從控制臺(tái)輸入
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
buffer = strin.readLine();
// 因?yàn)閞eadLine以換行符為結(jié)束點(diǎn)所以,結(jié)尾加入換行
buffer += "\n";
// 這里修改成向全部連接到服務(wù)器的用戶(hù)推送消息
for (Socket socket : socketMap.values()) {
OutputStream output = socket.getOutputStream();
output.write(buffer.getBytes("utf-8"));
// 發(fā)送數(shù)據(jù)
output.flush();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
/**
* 模擬添加信息進(jìn)入數(shù)據(jù)庫(kù)和內(nèi)存
* 
* @param messageBean
* @param scoket
*/
private void setChatMap(MessageBean messageBean, Socket scoket) {
// 將用戶(hù)信息存起來(lái)
if (userMap != null && userMap.get(messageBean.getUserId()) == null) {
userMap.put(messageBean.getUserId(), getUserInfoBean(messageBean.getUserId()));
}
// 將對(duì)應(yīng)的鏈接進(jìn)來(lái)的socket存起來(lái)
if (socketMap != null && socketMap.get(messageBean.getUserId()) == null) {
socketMap.put(messageBean.getUserId(), scoket);
}
}
/**
* 模擬數(shù)據(jù)庫(kù)的用戶(hù)信息,這里創(chuàng)建id不同的用戶(hù)信息
* 
* @param userId
* @return
*/
private UserInfoBean getUserInfoBean(int userId) {
UserInfoBean userInfoBean = new UserInfoBean();
userInfoBean.setUserIcon("用戶(hù)頭像");
userInfoBean.setUserId(userId);
userInfoBean.setUserName("admin");
userInfoBean.setUserPwd("123123132a");
return userInfoBean;
}
/**
* 將消息轉(zhuǎn)發(fā)給目標(biāo)好友
* 
* @param messageBean
*/
private void getFriend(MessageBean messageBean) {
if (socketMap != null && socketMap.get(messageBean.getFriendId()) != null) {
Socket socket = socketMap.get(messageBean.getFriendId());
String buffer = gson.toJson(messageBean);
// 因?yàn)閞eadLine以換行符為結(jié)束點(diǎn)所以,結(jié)尾加入換行
buffer += "\n";
try {
// 向客戶(hù)端發(fā)送信息
OutputStream output = socket.getOutputStream();
output.write(buffer.getBytes("utf-8"));
// 發(fā)送數(shù)據(jù)
output.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

3,(客戶(hù)端代碼)LoginActivity 登陸頁(yè)面修改可以登錄多人

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) {
int status = getLogin(chat_name_text.getText().toString().trim(), chat_pwd_text.getText().toString().trim());
if (status == -1 || status == 0) {
Toast.makeText(LoginActivity.this, "密碼錯(cuò)誤", Toast.LENGTH_LONG).show();
return;
}
getChatServer(getLogin(chat_name_text.getText().toString().trim(), chat_pwd_text.getText().toString().trim()));
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
});
}
/**
* 返回登陸狀態(tài),1為用戶(hù),2為另一個(gè)用戶(hù),這里模擬出兩個(gè)用戶(hù)互相通訊
*
* @param name
* @param pwd
* @return
*/
private int getLogin(String name, String pwd) {
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)) {
return 0;//沒(méi)有輸入完整密碼
} else if (name.equals("admin") && pwd.equals("1")) {
return 1;//用戶(hù)1
} else if (name.equals("admin") && pwd.equals("2")) {
return 2;//用戶(hù)2
} else {
return -1;//密碼錯(cuò)誤
}
}
/**
* 實(shí)例化一個(gè)聊天服務(wù)
*
* @param status
*/
private void getChatServer(int status) {
ChatAppliaction.chatServer = new ChatServer(status);
}
}

4,(客戶(hù)端代碼)ChatServer 聊天服務(wù)代碼邏輯的修改

public class ChatServer {
private Socket socket;
private Handler handler;
private MessageBean messageBean;
private Gson gson = new Gson();
// 由Socket對(duì)象得到輸出流,并構(gòu)造PrintWriter對(duì)象
PrintWriter printWriter;
InputStream input;
OutputStream output;
DataOutputStream dataOutputStream;
public ChatServer(int status) {
initMessage(status);
initChatServer();
}
/**
* 消息隊(duì)列,用于傳遞消息
*
* @param handler
*/
public void setChatHandler(Handler handler) {
this.handler = handler;
}
private void initChatServer() {
//開(kāi)個(gè)線程接收消息
receiveMessage();
}
/**
* 初始化用戶(hù)信息
*/
private void initMessage(int status) {
messageBean = new MessageBean();
UserInfoBean userInfoBean = new UserInfoBean();
userInfoBean.setUserId(2);
messageBean.setMessageId(1);
messageBean.setChatType(1);
userInfoBean.setUserName("admin");
userInfoBean.setUserPwd("123123123a");
//以下操作模仿當(dāng)用戶(hù)點(diǎn)擊了某個(gè)好友展開(kāi)的聊天界面,將保存用戶(hù)id和聊天目標(biāo)用戶(hù)id
if (status == 1) {//如果是用戶(hù)1,那么他就指向用戶(hù)2聊天
messageBean.setUserId(1);
messageBean.setFriendId(2);
} else if (status == 2) {//如果是用戶(hù)2,那么他就指向用戶(hù)1聊天
messageBean.setUserId(2);
messageBean.setFriendId(1);
}
ChatAppliaction.userInfoBean = userInfoBean;
}
/**
* 發(fā)送消息
*
* @param contentMsg
*/
public void sendMessage(String contentMsg) {
try {
if (socket == null) {
Message message = handler.obtainMessage();
message.what = 1;
message.obj = "服務(wù)器已經(jīng)關(guān)閉";
handler.sendMessage(message);
return;
}
byte[] str = contentMsg.getBytes("utf-8");//將內(nèi)容轉(zhuǎn)utf-8
String aaa = new String(str);
messageBean.setContent(aaa);
String messageJson = gson.toJson(messageBean);
/**
* 因?yàn)榉?wù)器那邊的readLine()為阻塞讀取
* 如果它讀取不到換行符或者輸出流結(jié)束就會(huì)一直阻塞在那里
* 所以在json消息最后加上換行符,用于告訴服務(wù)器,消息已經(jīng)發(fā)送完畢了
* */
messageJson += "\n";
output.write(messageJson.getBytes("utf-8"));// 換行打印
output.flush(); // 刷新輸出流,使Server馬上收到該字符串
} catch (Exception e) {
e.printStackTrace();
Log.e("test", "錯(cuò)誤:" + e.toString());
}
}
/**
* 接收消息,在子線程中
*/
private void receiveMessage() {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 向本機(jī)的8080端口發(fā)出客戶(hù)請(qǐng)求
socket = new Socket(SocketUrls.IP, SocketUrls.PORT);
// 由Socket對(duì)象得到輸入流,并構(gòu)造相應(yīng)的BufferedReader對(duì)象
printWriter = new PrintWriter(socket.getOutputStream());
input = socket.getInputStream();
output = socket.getOutputStream();
dataOutputStream = new DataOutputStream(socket.getOutputStream());
// 從客戶(hù)端獲取信息
BufferedReader bff = new BufferedReader(new InputStreamReader(input));
// 讀取發(fā)來(lái)服務(wù)器信息
String line;
while (true) {
Thread.sleep(500);
// 獲取客戶(hù)端的信息
while ((line = bff.readLine()) != null) {
Log.i("socket", "內(nèi)容 : " + line);
MessageBean messageBean = gson.fromJson(line, MessageBean.class);
Message message = handler.obtainMessage();
message.obj = messageBean.getContent();
message.what = 1;
handler.sendMessage(message);
}
if (socket == null)
break;
}
output.close();//關(guān)閉Socket輸出流
input.close();//關(guān)閉Socket輸入流
socket.close();//關(guān)閉Socket
} catch (Exception e) {
e.printStackTrace();
Log.e("test", "錯(cuò)誤:" + e.toString());
}
}
}).start();
}
public Socket getSocekt() {
if (socket == null) return null;
return socket;
}
}

如此一來(lái),代碼邏輯已經(jīng)從消息推送的邏輯修改成了單聊的邏輯了。

這個(gè)代碼可以讓用戶(hù)1和用戶(hù)2相互聊天,并且服務(wù)器會(huì)記錄下他們之間的聊天記錄。并且服務(wù)器還是擁有消息推送的功能。

以上所述是小編給大家介紹的Java Socket聊天室編程(二)之利用socket實(shí)現(xiàn)單聊聊天室,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • 關(guān)于MyBatis各種SQL操作詳解

    關(guān)于MyBatis各種SQL操作詳解

    這篇文章主要介紹了關(guān)于MyBatis各種SQL操作詳解,MyBatis 是一款優(yōu)秀的半自動(dòng)的ORM持久層框架,它支持自定義 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射,需要的朋友可以參考下
    2023-05-05
  • ThreadLocal原理及內(nèi)存泄漏原因

    ThreadLocal原理及內(nèi)存泄漏原因

    這篇文章主要介紹了ThreadLocal原理及內(nèi)存泄漏原因,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • 深入解析Java的Struts框架中的控制器DispatchAction

    深入解析Java的Struts框架中的控制器DispatchAction

    這篇文章主要介紹了深入解析Java的Struts框架中的控制器DispatchAction,Struts是Java的SSH三大web開(kāi)發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • SpringBoot RedisTemplate分布式鎖的項(xiàng)目實(shí)戰(zhàn)

    SpringBoot RedisTemplate分布式鎖的項(xiàng)目實(shí)戰(zhàn)

    本文主要介紹了SpringBoot RedisTemplate分布式鎖的項(xiàng)目實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • Java對(duì)象以Hash結(jié)構(gòu)存入Redis詳解

    Java對(duì)象以Hash結(jié)構(gòu)存入Redis詳解

    這篇文章主要介紹了Java對(duì)象以Hash結(jié)構(gòu)存入Redis詳解,和Java中的對(duì)象非常相似,卻不能按照J(rèn)ava對(duì)象的結(jié)構(gòu)直接存儲(chǔ)進(jìn)Redis的hash中,因?yàn)镴ava對(duì)象中的field是可以嵌套的,而Redis的Hash結(jié)構(gòu)不支持嵌套結(jié)構(gòu),需要的朋友可以參考下
    2023-08-08
  • 詳解Java線程池和Executor原理的分析

    詳解Java線程池和Executor原理的分析

    這篇文章主要介紹了詳解Java線程池和Executor原理的分析的相關(guān)資料,這里提供實(shí)例及分析原理幫助大家理解這部分知識(shí),需要的朋友可以參考下
    2017-07-07
  • IDEA新建的Moudle失效顯示為灰色的完美解決方案

    IDEA新建的Moudle失效顯示為灰色的完美解決方案

    這篇文章主要介紹了IDEA新建的Moudle失效顯示為灰色,本文通過(guò)圖文并茂的形式給大家分享完美解決方案,需要的朋友可以參考下
    2023-09-09
  • Java微信支付之關(guān)閉訂單

    Java微信支付之關(guān)閉訂單

    這篇文章主要為大家詳細(xì)介紹了Java微信支付之關(guān)閉訂單,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • 解決Spring Cloud Feign 請(qǐng)求時(shí)附帶請(qǐng)求頭的問(wèn)題

    解決Spring Cloud Feign 請(qǐng)求時(shí)附帶請(qǐng)求頭的問(wèn)題

    這篇文章主要介紹了解決Spring Cloud Feign 請(qǐng)求時(shí)附帶請(qǐng)求頭的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Java響應(yīng)式編程之handle用法解析

    Java響應(yīng)式編程之handle用法解析

    這篇文章主要介紹了Java響應(yīng)式編程之handle用法解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10

最新評(píng)論