實現socket通信
socket概述
Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。
1.Socket是一個網絡通信的套接字(接口)
2.socket實現過程:服務器端先初始化Socket,然後與端口綁定(bind), 對端口進行監聽(listen),調用accept阻塞,等待客戶端連接。
在這時如果有個客戶端初始化一個Socket,然後連接服務器(connect),
如果連接成功,這時客戶端與服務器端的連接就建立了。
客戶端發送數據請求,服務器端接收請求並處理請求,然後把迴應數據發送給客戶端,客戶端讀取數據,
最後關閉連接,一次交互結束。
1)配置:
服務器:
a.socket()創建socket對象
b.bind()爲socket對象綁定協議,賦予名字
c.listen()監聽此socket,將socket從默認主動類型改爲被動類型
客戶端:
a.socket()創建一個socket對象
b.connect()連接服務器的socket對象
2)服務器,客戶端都可使用read(),write()等函數進行通信
採用Java語言編寫的socket服務端
採用Android編寫的socket客戶端
socket服務端
演示圖片如下:
目標:實現上圖演示的功能:
1.創建主函數,功能:首先創建服務並監聽請求,在根據輸入的內容執行不同的功能.
以下只提供了部分代碼如下:
public static void main(String[]args) throws IOException { //主入口函數.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line; boolean isExit = false;//變量初始化
ClientManager.startServer();//開啓服務器並監聽請求 服務器發送數據(線程
while (!isExit){ line = br.readLine();
if (line.startsWith("exit")){ break; }//退出程序
if (line.startsWith("send")){ sendMessage(line);}//發送數據至客戶端
else if (line.startsWith("save")) { SaveToFile(line);}//保存客戶端數據到某一個文件
else if (line.startsWith("list")) { printTotal();}//獲取連接列表
else if (line.startsWith("all")) { allSendMsg(line);}//發送消息到所有的客戶端連接
else { System.out.println("輸入錯誤 請重新輸入");} }
ClientManager.shutDown(); // 關閉 清空
}
2.實現socket服務端的構造方法及監聽事件的線程操作.
public class ClientManager {
public static String text_what=" "; //客戶端向服務端發送的消息..
private static ServerThread serverThread = null;
private static int sum = 0; //連接數量
private static Map<String, Socket> clientMap = new HashMap<String, Socket>();
private static List<String> clientList = new ArrayList<String>();
private static class ServerThread implements Runnable {
private ServerSocket server;
private int port = 9896;//54321;
private boolean isExit = false;// 一個boolean類型的判斷 默認是退出狀態false
// 構造方法初始化
public ServerThread() {//啓動server
try {
server = new ServerSocket(port); //啓動server及端口號 //ServerSocket的構造方法.
System.out.println("啓動server,端口號:" +server.getLocalPort()); }
catch (IOException e) { e.printStackTrace();}
}
public void run() {
try {
while (!isExit) {
// 等待連接
System.out.println("等待手機的連接中... ...");
final Socket socket = server.accept(); //等待客戶端的連接,當客戶端請求連接時,返回一個Socket.
System.out.println("獲取的手機IP地址及端口號:" + socket.getRemoteSocketAddress().toString());
//因爲考慮到多手機連接的情況 所以加入線程鎖 只允許單線程工作
new Thread(new Runnable() {
private String text;
public void run() {
try {
synchronized (this) {++sum; // 在這裏考慮到線程總數的計算 也代表着連接手機的數量
// 存入到集合和Map中爲羣發和單獨發送做準備
String string = socket.getRemoteSocketAddress().toString();
clientList.add(string); clientMap.put(string, socket); }
// 定義輸入輸出流
InputStream is = socket.getInputStream();
// 接下來考慮輸入流的讀取顯示到PC端和返回是否收到
byte[] buffer = new byte[102400]; int len;//(1kb數據以內有效.)
while ((len = is.read(buffer)) > -1) { //不斷讀取來自客戶端的消息
text = new String(buffer, 0, len);
text=new String(text.getBytes("GBK"));
new net_untils().saveTofileMode("socket_list",text,true,0);
int net_mode=-1;
if ((new net_untils().isInteger(text))&&(!text.equalsIgnoreCase("0")))
{net_mode=Integer.parseInt(text); }//若收到的數據含有數字則不再顯示直接根據固定對應方式迴應客戶端.
else System.out.println("收到的數據爲:" + text); text_what=text;//(客戶端之間交流時得到的數據)
//收到的特殊字符串後若爲保存文件的格式則自動保存文件.
if (net_mode==1) sendMsgAll("(自動回覆:獲取該服務器系統信息)\n本服務器鏈接數量爲"+sumTotal()+
"\n本服務器的IP地址和端口爲:"+socket.getLocalSocketAddress().toString()+
"\n連接的客戶端IP地址和端口爲"+socket.getRemoteSocketAddress().toString()
);
if (net_mode==2) sendMsgAll( new net_untils().Read_form_file("工作任務.txt")); //自動讀取固定文件數據
if (net_mode==9) sendMsgAll( MU_img() ); //向客戶端發送某路徑下的文件夾
if (text.substring(0,1).equalsIgnoreCase("0")) {
new net_untils().saveTofile("工作任務.txt","系統消息(已保存至重要文件)");}
if (text.substring(0, 1).equalsIgnoreCase("8")) {
String wht=new net_untils().Str_lastOne(text);
switch (wht) {
case "txt": //向客戶端發送文件內的文本..
wht=new net_untils().Read_form_path( text.substring(1, text.length()) );
sendMsgAll("已獲取文件:\n"+wht); break;
case "mp3": break;
case "wav": //在本設備內播放.wav的文件..
try { new untils().music(text.substring(1, text.length()) );}
catch (Exception e) { e.printStackTrace();}
break;
default:
wht=MU_path( text.substring(1, text.length()) );
sendMsgAll(wht ); break;
}
}
} }
catch (IOException e) { e.printStackTrace();}
finally {
System.out.println("關閉連接:" + socket.getRemoteSocketAddress().toString());
synchronized (this) { --sum;
String string = socket.getRemoteSocketAddress().toString();
clientMap.remove(string); clientList.remove(string); } }
} }).start(); } }
catch (IOException e) { e.printStackTrace();}
}
// 關閉server
public void stop() {
isExit = true; if (server != null) {
try { server.close(); //關閉服務器socket
System.out.println("已關閉server"); }
catch (IOException e) { e.printStackTrace();} }
}
}
public static ServerThread startServer() { // 功能:啓動server
System.out.println("開啓server");
if (serverThread != null) { //變量不爲空時
System.out.println("server不爲null正在重啓server");
shutDown(); } // 以下爲關閉server和socket
// 初始化
serverThread = new ServerThread();//啓動Ip及端口,不斷監聽請求並作出響應.
new Thread(serverThread).start();//開啓線程
System.out.println("開啓server成功");
return serverThread;
}
}
3.可以通過這個類讀取服務端的文件,我是在電腦E:/盤中創建的文件夾,這個文件夾專門作爲服務器與客戶端通信內容的文件,大家可以隨意創建,
public class net_untils {
public String Str_lastOne(String wht) { //獲取字符串的後綴名,即'.'字符之後的內容
StringBuffer strbuf=new StringBuffer(wht);
String strnf="";
for (int i=0;i<strbuf.length();i++) {
char whr=strbuf.charAt(i);
if (whr=='.') { strnf=strbuf.substring(i+1, strbuf.length()).toString();
break;} }
return strnf;
}
public static boolean isInteger(String str) {
Pattern pattern=Pattern.compile("[0-9]");//^[-\\+]?[\\d]*$
return pattern.matcher(str).matches();
}
public void saveTofile(String filename,String tip) throws IOException {//保存文件並給出提示消息
OutputStream ous = null;
try {
ous = new FileOutputStream(new File("E://personal//save_data/",filename));//同名會覆蓋
ous.write(ClientManager.text_what.getBytes());
System.out.println(tip);}
catch (FileNotFoundException e) { e.printStackTrace();ous.close();}
}
public void saveTofileMode(String filename,String filecontent,boolean append,int listname) {
FileWriter fw=null;
try {String tip=null;
fw=new FileWriter("E://personal//save_data/"+filename,append);
if (listname==-1) tip="Server:"; else if (listname==0) tip="Client:"; else tip=String.valueOf(listname);
fw.write(tip+filecontent+"\n"); }
catch (Exception e) { System.out.println("書寫日誌發生錯誤:"+e.toString());}
finally { try {fw.close();} catch (IOException r) {r.printStackTrace();} }
}
public String Read_form_file(String filename) {//文件打開方式需要GBK模式
java.io.File file = new java.io.File("E:/personal/save_data/"+filename);
FileInputStream in = null;
if (!file.exists()){ return "file is not found";}
//如果文件不存在,我們就拋出異常或者不在繼續執行
//在實際應用中,儘量少用異常,會增加系統的負擔
try {
in = new FileInputStream(file);
byte bytArr[] = new byte[1024];
int len = in.read(bytArr);
String fstr=new String(bytArr, 0, len);
in.close(); fstr=new String (fstr.getBytes("GB2312"));
return fstr;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String Read_form_path(String filename) {//文件打開方式需要GBK模式
java.io.File file = new java.io.File(filename);
FileInputStream in = null;
if (!file.exists()){ return "file is not found";}
//如果文件不存在,我們就拋出異常或者不在繼續執行
//在實際應用中,儘量少用異常,會增加系統的負擔
try {
in = new FileInputStream(file);
byte bytArr[] = new byte[1024];
int len = in.read(bytArr);
String fstr=new String(bytArr, 0, len);
in.close(); fstr=new String (fstr.getBytes("GB2312"));
return fstr;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
可以在其中添加很多有趣的功能,如通過客戶端播放服務器文件下的音視頻文件等等…
socket通信的服務端到此就介紹完了,這裏只貼上了部分代碼,感興趣的話下方有下載鏈接
socket客戶端
首先就是新建Android應用,注意要在Manifest.xml文件中添加訪問internet的權限,在res中創建layout和添加圖片
演示圖片如下:
目標:實現上圖功能:
1.主layout:
<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">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="600px"
android:orientation="horizontal">
<TextView
android:id="@+id/texr"
android:layout_width="300px"
android:layout_height="600px"
android:scrollbars="vertical"
android:hint="請輸入指令:"/>
<TextView android:id="@+id/texd"
android:layout_width="fill_parent"
android:layout_height="600px"
android:hint="設備文本"/>
</LinearLayout>
<!--android:ellipsize="marquee"
android:singleLine="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:inputType="textMultiLine" -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/eidt"
android:layout_width="500px"
android:layout_height="wrap_content"
android:hint="(數字開頭代表某功能)"/>
<Button
android:id="@+id/shujushangchuan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="發送消息"/>
<Button android:id="@+id/listen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播放"
android:onClick="clik"/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:gravity="right"
android:layout_height="wrap_content"
android:background="@drawable/footer_bar">
<Button android:id="@+id/close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="關閉連接"
android:onClick="coo"/>
<Button android:id="@+id/connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="重新連接"
android:onClick="coo"/>
<TextView android:id="@+id/te_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="初始化.."
android:background="#FF000000"
android:textColor="#FFFFFFFF"/>
<ImageButton
android:id="@+id/re"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/back"
android:layout_gravity="right"/>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button android:id="@+id/co_pa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="電腦文件路徑"/>
</LinearLayout>
<LinearLayout
android:layout_width="700px"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView android:id="@+id/sh_path"
android:layout_width="700px"
android:layout_height="200px" />
<ListView android:id="@+id/sh_ew"
android:layout_width="700px"
android:visibility="gone"
android:layout_height="fill_parent"></ListView>
<Spinner
android:id="@+id/spinner2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
2.socket客戶端:
…註釋已經很完整了
public class And_client extends Activity {
private TextView chatmessage=null; //文本視圖顯示聊天記錄.(顯示數據交流過程)
private EditText sendmessage=null; //用戶輸入編輯框.(數據源可以是編輯框或者是文件)
private Button send_button=null,lis_bu; //發送按鈕.(發送數據的行爲)
private static String HOST="192.168.0.108"; //服務器的IP地址.
private static int PORT=9896; //服務器的端口號.
private Socket socket=null; //聲明套接字類,傳輸數據.
private String mess_s=""; //待保存的數據.
private Spinner spinner;
private ArrayAdapter<String> aspnStars;
private String Rpath="";
private List<String> paths=null; //存放路徑
private String rootPath="E:/personal/save_data/name/";//服務端設備的起始目錄
private TextView mPath; //顯示正在訪問的路徑..
private TextView te_show; //顯示相關狀態消息..
private TextView te_text; //顯示設備文件文本..
TextToSpeech mtts;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
chatmessage=(TextView)findViewById(R.id.texr);
chatmessage.setMovementMethod(ScrollingMovementMethod.getInstance());
sendmessage=(EditText)findViewById(R.id.eidt); //將服務器作爲手機訪問的一部分.
send_button=(Button)findViewById(R.id.shujushangchuan);
spinner=(Spinner)findViewById(R.id.spinner2); spinner.setVisibility(View.INVISIBLE);
mPath=(TextView)findViewById(R.id.sh_path); mPath.setText("服務器文件路徑爲:");
te_show=(TextView)findViewById(R.id.te_show);
te_text=(TextView)findViewById(R.id.texd);
lis_bu=(Button)findViewById(R.id.listen); lis_bu.setVisibility(View.GONE);
mtts=new TextToSpeech(And_client.this,new TTSListener());
initSocket();
send_button.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
String message=sendmessage.getText().toString(); sendmessage.setText("");
new ClientWrite(socket, message).start();//作用類似於sendMsg(message);//發送消息
new Tool_2().txtviw_ad(chatmessage, "Client:"+message);
new Tool_2().reshtew(chatmessage, chatmessage.getText().toString());
} });
ImageButton re=(ImageButton)findViewById(R.id.re);
re.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
final Button sedf=(Button)findViewById(R.id.co_pa);
sedf.setOnClickListener(new OnClickListener() { //獲取電腦某路徑下的文件列表
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
String message="9";//+"獲取服務器文件";
sedf.setEnabled(false);
new ClientWrite(socket, message).start();
new Tool_2().txtviw_ad(chatmessage, "Client(系統消息):已發送重要消息");
new Tool_2().reshtew(chatmessage, chatmessage.getText().toString());
spinner.setVisibility(View.VISIBLE);
//ReNoList(1,mess_s);
ReSpinner(mess_s);
}
});
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
//String[] res=getResources().getStringArray(R.array.Stars);
String str=(String)arg0.getItemAtPosition(arg2);
if (str.equalsIgnoreCase("請選擇")) { ;}
else {
String str_la=new Tool_Str().Str_lastOne(str);
switch (str_la) {
case "txt":
case "mp3":
case "wav":
rootPath+=str; te_show.setText("正在執行文件");
break;//若不是文件夾..
default: str_la="不是";
te_show.setText("正在訪問文件夾"); break;
}
//路徑末尾帶有'/'的處理..
if (str_la.equalsIgnoreCase("不是")) {
if (arg2==1) { rootPath="E:/personal/save_data/name/";} //回到根目錄
else if (arg2==2) { rootPath=new Tool_Str().last_path(rootPath);} //回到上一目錄
else rootPath+=str+"/"; } //若是文件夾
//發送帶有加前頭爲8的路徑,向服務器說明是訪問服務器設備文件..
String message="8"+rootPath; mPath.setText(message);
new ClientWrite(socket, message).start();
new Tool_2().txtviw_ad(chatmessage, "Client(系統消息):已發送重要消息");
new Tool_2().reshtew(chatmessage, chatmessage.getText().toString());
new tool_utils.thread_utils().sleepForInSecs(1); //有等待時間的??????防止socket錯亂????????????????
//服務器向客戶端發送的消息:..
switch (str_la) {
case "txt": showDialog(1);
//rootPath=new Tool_Str().last_path(rootPath);
break; //顯示設備文件文本內容..
case "mp3":
case "wav":
//rootPath=new Tool_Str().last_path(rootPath);
break;
default: te_text.setText(""); lis_bu.setVisibility(View.GONE);
spinner.setVisibility(View.VISIBLE);
ReSpinner(mess_s); break;
}
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
}); //注:使用列表讀取數據存在延遲..可能繪製列表的時間要多
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
try { socket.close();
new Tool_2().showClickMessage(And_client.this,"已關閉連接",1); } //退出時自動關閉連接
catch (IOException e) { e.printStackTrace();}
}
public void coo(View v) {
switch (v.getId()) {
case R.id.close:
try { socket.close();
new Tool_2().showClickMessage(And_client.this,"已關閉連接",1); } //手動關閉連接.
catch (IOException e) { e.printStackTrace();}
break;
case R.id.connect:
initSocket(); new Tool_2().showClickMessage(And_client.this, "已重新連接", 1); //重新連接.
break;
}
}
public void initSocket() { //初始化socket
final Handler handler=new MyHandler();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
socket=new Socket(HOST, PORT); //通過指定IP和端口號創建套接字.
InputStream inputStream = socket.getInputStream();// 接收來自服務器的消息
byte[] buffer = new byte[102400]; int len;
while ((len = inputStream.read(buffer)) != -1) {
String s = new String(buffer, 0, len);//開啓的線程更新主UI線程
Message message = Message.obtain();
message.what = 1; message.obj = s;//線程IDwhat,線程數據obj
mess_s=s; handler.sendMessage(message); }
}
catch (Exception e) { e.printStackTrace(); } //打印異常並生成對話框.
} }).start();
}
public class MyHandler extends Handler { //=new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what==1) {
final String s=(String)msg.obj;
runOnUiThread(new Runnable() {
public void run() {
new Tool_2().txtviw_ad(chatmessage, "Server:"+s);
new Tool_2().reshtew(chatmessage, chatmessage.getText().toString());
}
//string(讀取數據後,若爲保存文件的格式則自動保存文件)????????
//若讀取數據爲exit則退出該socket
}); }
}
};
private void actCMenu1(final String str) {
//增加文件方法
LayoutInflater factory=LayoutInflater.from(And_client.this);
View myView=factory.inflate(R.layout.rename_alert_dialog,null);
final EditText myEditText=(EditText)myView.findViewById(R.id.mEdit);
myEditText.setHint("文件名"); //對文件名進行檢查防止文件重名
android.content.DialogInterface.OnClickListener listener2=new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { /* 取得修改後的文件路徑 */
final String filenae=myEditText.getText().toString();
if (mess_s.equalsIgnoreCase("")) {
new Tool_2().showClickMessage(And_client.this, "保存失敗",1);
}
else new Tool_1().writeFileToPa(str, filenae+".txt", mess_s, 1);
} }; /* 重新產生文件列表的 ListView */
AlertDialog newFileDialog=new AlertDialog.Builder(And_client.this).create(); /* create 更改檔名時跳出的 Dialog */
newFileDialog.setView(myView); newFileDialog.setButton("確定",listener2); /* 設置更改檔名點擊確認後的 Listener */
newFileDialog.setButton2("取消",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { ;} }); newFileDialog.show();
}
//將定義的mStars數據載入到Spinner1組件
private void ReSpinner(String mbpath) { //加載傳回的內容..
spinner.setVisibility(View.VISIBLE); spinner.setSelection(0);
paths=new ArrayList<String>();
paths.add("請選擇"); paths.add("根目錄");
if (new Tool_Str().cha_num(mPath.getText().toString(), '/')>1) {
paths.add("上一層"); }
StringBuffer R_path=new StringBuffer(mbpath);
StringBuffer S_path=new StringBuffer(10000);
for (int i=0,j=1;i<R_path.length();i++) {
char pa=R_path.charAt(i);
if (pa=='\n') {
j+=1; paths.add(S_path.toString());
S_path=new StringBuffer(10000); }
else S_path.append(pa);
}
aspnStars=new ArrayAdapter<String>(And_client.this,android.R.layout.simple_spinner_item,paths);
aspnStars.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(aspnStars);
//txte.setText( String.valueOf( spinner.getAdapter().getCount()) );
}
private class TTSListener implements OnInitListener{
public void onInit(int status){
if (status==TextToSpeech.SUCCESS){//設置語言
int result=mtts.setLanguage(Locale.CHINA);//若返回-2即不支持該語言
if (result==TextToSpeech.LANG_MISSING_DATA||result==TextToSpeech.LANG_NOT_SUPPORTED){ ;} //語言不可用,TTS使用失敗
else { mtts.speak("", TextToSpeech.QUEUE_FLUSH,null);} } }
}
public void clik(View view) {
switch (view.getId()) {
case R.id.listen:
mtts.speak(te_text.getText().toString(),TextToSpeech.QUEUE_FLUSH, null);
}
}
public Dialog onCreateDialog(int id) {//對話框
switch (id) {
case 1:return buildDialog1(And_client.this); //規則展示項目.
}
return null;
}
private Dialog buildDialog1(final Context context) { //各個部門功能追求的理念信念 設定..
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("正在打開文件..");builder.setIcon(R.drawable.clock);
builder.setMessage("打開");
builder.setPositiveButton("打開", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
lis_bu.setVisibility(View.VISIBLE); te_text.setText(mess_s);
}
})
.setNegativeButton("返回",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) { ; } });
return builder.create();
}
}
3.我把寫入socket的代碼單獨寫入一個類中:
public class ClientWrite extends Thread{
private Socket client;
private String mess;
public ClientWrite(Socket client,String mess) {
this.client=client;
this.mess=mess; }
public void run() {
try {
OutputStream outputStream = null;
outputStream = client.getOutputStream();
outputStream.write((mess).getBytes("GBK"));//("utf-8"));
outputStream.flush();// 清空緩存
}
catch (Exception e) { e.printStackTrace();}
}
}
socket通信的客戶端到此就介紹完了,這裏只貼上了部分代碼,感興趣的話下方有下載鏈接
socket示例總結
能夠成功運行的條件:
1.客戶端服務端都是在同一網絡環境下,涉及在不同網絡下通信還需要什麼ip映射之類的知識,下次我在詳細說明.
2.客戶端涉及的ip地址是在命令提示符中獲取的.
遇到的問題:
socket通信會涉及到編碼問題,關於編碼問題請在下載鏈接中獲取
服務端採用線程和監聽列表組成,因爲可能會有多個客戶端連接
改進功能:
1.通信內容會有數據大小的限制,可以將數據分割成幾個包再進行發送
2.豐富服務端的功能,如自動瀏覽文件夾下的圖片音視頻等等…
3.讀取服務端內容時由於網絡原因有時會出現內容接收不到或者延遲接收等等情況
4.可以在客戶端提供下載服務端文件夾下的圖片等等…
下載鏈接
我也僅僅是實現了socket通信,也不是理解的特別明白,達不到那種
"知其然在知其所以然"的境界…