今天又是元氣滿滿學習的一天,從上章內容我們可以對socket tcp協議服務端和客戶端的簡單的信息傳遞接收進行學習,對socket通信有了一丟丟的瞭解,
流程圖:
總結:tcp socket通信主要是再InputStream 和 OutputStream之間進行數據的讀取和寫入
其中我們可以通過 socket.getInputStream() 或者 socket.getOutputStream()拿到實例 然後進行讀取和寫入的功能
其中 socket.getInputStream()爲輸入流(讀取) 收到的數據在這裏
socket.getOutputStream()爲輸出流(寫入) 發送的數據在這裏
好了,廢話不多比比 開始我們的簡易聊天室的實現 —> 詳細的實現請看代碼中的註釋
eclipse 服務端
public class Server {
public static final int PORT = 12345;//端口號
private List<Socket> mList = new ArrayList<Socket>();
private ServerSocket server = null;
private ExecutorService myExecutorService = null;
public static void main(String[] args) {
// TODO Auto-generated method stub
new Server();
}
public Server(){
//服務器創建流程如下
try {
//1.創建ServerSocket
server = new ServerSocket(PORT);
//創建線程池
myExecutorService = Executors.newCachedThreadPool();
System.out.println("服務端運行中...\n");
Socket client = null;
while(true)
{
//2.等待接收請求 這裏接收客戶端的請求
client = server.accept();
System.out.println("得到客戶端連接:" + client);
mList.add(client);
//初始化完成
//執行線程
myExecutorService.execute(new Service(client));
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class Service implements Runnable{
private Socket socket;
private BufferedReader in = null;
private String msg = "";
public Service(Socket socket){
this.socket = socket;
try {
//3.接收請求後創建鏈接socket
//4.通過InputStream outputStream進行通信
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//可拆分
// InputStream is = socket.getInputStream();
//
// InputStreamReader ins = new InputStreamReader(is);
//
// in = new BufferedReader(ins);
msg = "用戶:" +this.socket.getInetAddress() + "~加入了聊天室"
+"當前在線人數:" +mList.size();
this.sendmsg();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
if((msg=in.readLine())!=null){
System.out.println("從客戶端接收到的消息爲:" + msg);
if(msg.equals("bye")){
System.out.println("~~~~~~~~~~~~~");
mList.remove(socket);
in.close();
msg = "用戶:" + socket.getInetAddress()
+ "退出:" +"當前在線人數:"+mList.size();
//5.關閉資源
socket.close();
this.sendmsg();
break;
}else{
msg = socket.getInetAddress() + " 說: " + msg;
this.sendmsg();
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//爲連接上服務端的每個客戶端發送信息
public void sendmsg()
{
System.out.println(msg);
int num = mList.size();
for(int index = 0;index < num;index++)
{
Socket mSocket = mList.get(index);
PrintWriter pout = null;
try {
//PrintWriter 和BufferWriter使用方法相似
pout = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(mSocket.getOutputStream(),"UTF-8")),true);
pout.println(msg); //將輸出流包裝爲打印流
}catch (IOException e) {e.printStackTrace();}
}
}
}
}
從上面的服務器端我們可以知道服務器端先將客戶端發送的數據進行存儲到msg中 然後通過PrintWriter 又發送到了客戶端
PrintWriter 詳解:
//PrintWriter 和BufferWriter使用區別
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bufw.write("hello,server!");
bufw.newLine();
bufw.flush();
//上面的4行代碼用PrintWriter實現只需要兩行。
PrintWtriter out = new PrintWriter(s.getOutputStream, true);
out.println("hello,server!");
安卓客戶端
public class ChatRoom extends AppCompatActivity implements Runnable{
//定義相關變量,完成初始化
private TextView txtshow;
private EditText editsend;
private Button btnsend;
private static final String HOST = "192.168.30.83";
private static final int PORT = 12345;
private Socket socket = null;
private BufferedReader in = null;
private PrintWriter out = null;
private String content = "";
private StringBuilder sb = null;
//定義一個handler對象,用來刷新界面
public Handler handler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 0x123) {
sb.append(content);
Log.i("wotainanl","@@"+sb);
txtshow.setText(sb.toString());
}
}
;
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat_room);
sb = new StringBuilder();
txtshow = findViewById(R.id.txtshow);
editsend = findViewById(R.id.editsend);
btnsend = findViewById(R.id.btnsendza);
//當程序一開始運行的時候就實例化Socket對象,與服務端進行連接,獲取輸入輸出流
new Thread() {
public void run() {
try {
socket = new Socket(HOST, PORT);
//獲取輸入輸出流
in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
Log.i("wotainanl","in"+in+"@@"+out);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
// 爲發送按鈕設置點擊事件
btnsend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final String msg = editsend.getText().toString();
if (socket.isConnected()) {
if (!socket.isOutputShutdown()) {
new Thread(new Runnable() {
@Override
public void run() {
out.println(msg);
}
}).start();
Log.i("wotainanl",msg);
}
}
}
});
new Thread(ChatRoom.this).start();
}
//重寫run方法,在該方法中輸入流的讀取
@Override
public void run() {
try {
while (true) {
if (socket.isConnected()) {
if (!socket.isInputShutdown()) {
if ((content = in.readLine()) != null) {
content += "\n";
handler.sendEmptyMessage(0x123);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
over!
Socket TCP的通信流程:
傳輸前先開服務端,accept,等客戶端接入,然後獲得 客戶端socket然後進行IO操作
本文參考:https://www.kancloud.cn/kancloud/android-tutorial/87240