以爲爲demo路徑 (包含服務器端代碼以及客戶端代碼,基於TCP傳輸的demo)
注意一個細節!就是編碼問題,一定要統一流的編碼格式
Socket 的傳輸數據的兩種方式:
1、TCP 可靠協議,假設服務器發送消息給客戶端,客戶端收到之後,會有一個迴應給服務器端,告訴它“我已經收到了”,如果服務器在設定的時間沒沒有收到客戶端的反饋,則認爲消息發送不成功,繼續發送 ,所以TCP協議是安全的,可靠協議,很少出現丟包的情況
2、UDP 不可靠協議,服務器端只管發送數據給客戶端,無論你有沒有收到,都不會做處理, 一般用來做直播。視頻通過這些用的比較多
首先看服務器的代碼:
public class ServerSockt {
//因爲可能不止一個客戶端,所以採用集合的方式來管理socket
public static List<Socket> lists = Collections.synchronizedList( new ArrayList<Socket>());
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8285);
while( true){
Socket s =ss.accept();
lists.add(s);
//開啓一個線程 接受與發送消息給客戶端
new Thread( new ServerThread(s)).start();
}
} catch (Exception e) {
}
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ServerThread extends Thread {
private Socket socket;
private BufferedReader br;
public ServerThread(Socket socket) throws Exception {
super();
this. socket = socket;
//編碼一定要統一
br = new BufferedReader( new InputStreamReader(socket.getInputStream(),"UTF-8" ));
}
@Override
public void run() {
super.run();
try {
String msg;
while((msg= br.readLine())!= null){
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss" );//格式化日期
//將接收到的字符串讀取出來,加上日期返回給客戶端,編碼一定要統一
PrintStream ps = new PrintStream(socket .getOutputStream(), true,"UTF-8" );
ps.println( "服務器說還給你:" +msg+">>>>>" +df.format( new Date()));
System. out.println(msg);
ps.flush();
}
} catch (Exception e) {
}
}
}
注意一個細節!就是編碼問題,一定要統一流的編碼格式
Android客戶端的代碼
public class MainActivity extends AppCompatActivity {
private EditText text; //文本框,要發送給服務器的數據
private Button btnSocket; //發送消息的按鈕
private ListView listView; //消息列表的ListView
private MsgAdapter adapter; //消息適配器
private List<String> list = new ArrayList<>();//ListView的數據源
private Socket socket = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (EditText) findViewById(R.id.text);
btnSocket = (Button) findViewById(R.id.button);
listView = (ListView) findViewById(R.id.msgList);
adapter = new MsgAdapter(MainActivity.this, list);
listView.setAdapter(adapter);
//開始的時候,我直接放在主線程,直接出現不能在主線程的工作的錯誤,於是開啓了一個線程
new Thread(new Runnable() {
@Override
public void run() {
socket();
}
}).start();
//發送消息的按鈕,發送消息到服務器是異步的,所以也只能另開一個線程
btnSocket.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
sendMsg();
}
}).start();
}
});
}
/**
* 初始化Socket
*/
private void socket() {
try {
if (socket == null) {
socket = new Socket("192.168.11.150", 8285);
}
receiveMsg();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 發送消息的方法
*/
public void sendMsg() {
PrintStream writer = null;
try {
String msg = "客戶端說:" + text.getText().toString();
//此處一定要設置編碼的格式,一定要和服務器統一,否則會出現亂碼的情況
writer = new PrintStream(socket.getOutputStream(), true, "UTF-8");
writer.println(msg);
writer.flush();
list.add(msg);
handler.sendEmptyMessage(0);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 接收到來自服務器的消息
*/
public void receiveMsg() {
BufferedReader br = null;
try {
//此處一定要設置編碼的格式,一定要和服務器統一,否則會出現亂碼的情況
br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
String msg;
while ((msg = br.readLine()) != null) {
list.add(msg);
handler.sendEmptyMessage(0);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
adapter.notifyDataSetChanged();
}
};
}