Transmission Control Protocol/Internet Protocol的簡(jiǎn)寫湿镀,中譯名為傳輸控制協(xié)議/因特網(wǎng)互聯(lián)協(xié)議厅贪,又名網(wǎng)絡(luò)通訊協(xié)議北专,是Internet最基本的協(xié)議、Internet國(guó)際互聯(lián)網(wǎng)絡(luò)的基礎(chǔ)琴许,由網(wǎng)絡(luò)層的IP協(xié)議和傳輸層的TCP協(xié)議組成聋涨。TCP/IP 定義了電子設(shè)備如何連入因特網(wǎng)御板,以及數(shù)據(jù)如何在它們之間傳輸?shù)臉?biāo)準(zhǔn)。協(xié)議采用了4層的層級(jí)結(jié)構(gòu)牛郑,每一層都呼叫它的下一層所提供的協(xié)議來完成自己的需求怠肋。通俗而言:TCP負(fù)責(zé)發(fā)現(xiàn)傳輸?shù)膯栴},一有問題就發(fā)出信號(hào)淹朋,要求重新傳輸笙各,直到所有數(shù)據(jù)安全正確地傳輸?shù)侥康牡亍6鳬P是給因特網(wǎng)的每一臺(tái)聯(lián)網(wǎng)設(shè)備規(guī)定一個(gè)地址础芍。
通俗的說TCP/IP就是一些列的網(wǎng)絡(luò)通訊規(guī)則杈抢。
在TCP/IP參考模型中,將網(wǎng)絡(luò)分為以下幾層:
應(yīng)用層
傳輸層
網(wǎng)際層
主機(jī)至網(wǎng)絡(luò)層
而java中的網(wǎng)絡(luò)編程一般是在傳輸層仑性,而其他情況下都是在應(yīng)用層進(jìn)行開發(fā)(如java web/android的App開發(fā)等等)
網(wǎng)絡(luò)通訊要素
IP地址:InetAddress
-網(wǎng)絡(luò)中設(shè)備的標(biāo)識(shí)
-不易記憶惶楼,可用主機(jī)名
-本地回環(huán)地址:127.0.0.1 主機(jī)名:localhost
端口號(hào)
-用于標(biāo)識(shí)進(jìn)程的邏輯地址,不同進(jìn)程的標(biāo)識(shí)
-有效端口:0~65535诊杆,其中0~1024系統(tǒng)使用或保留端口歼捐。
傳輸協(xié)議
-通訊的規(guī)則
-常見協(xié)議:TCP,UDP
class IPDemo {
public static void main(String[] args) throws Exception {
// 返回本機(jī)主機(jī)名
// InetAddress i = InetAddress.getLocalHost();
// System.out.println(i.toString());
// System.out.println("address:"+i.getHostAddress());
// System.out.println("name:"+i.getHostName());
InetAddress ia = InetAddress.getByName("thinkpad-sl400");
System.out.println("address:" + ia.getHostAddress());
System.out.println("name:" + ia.getHostName());
}
}
UDP與TCP
UDP的特點(diǎn)
- 將數(shù)據(jù)及源和目的封裝成數(shù)據(jù)包中晨汹,不需要建立連接
- 每個(gè)數(shù)據(jù)報(bào)的大小在限制在64k內(nèi)
- 因無連接豹储,是不可靠協(xié)議
- 不需要建立連接,速度快
面向無連接淘这,不管對(duì)方在不在都會(huì)發(fā)送數(shù)據(jù)剥扣,而且數(shù)據(jù)容易丟失
TCP的特點(diǎn):
建立連接,形成傳輸數(shù)據(jù)的通道铝穷。
在連接中進(jìn)行大數(shù)據(jù)量傳輸
通過三次握手完成連接钠怯,是可靠協(xié)議
必須建立連接,效率會(huì)稍低
Socket
Socket就是為網(wǎng)絡(luò)服務(wù)提供的一種機(jī)制曙聂。
通信的兩端都有Socket晦炊。
網(wǎng)絡(luò)通信其實(shí)就是Socket間的通信。
數(shù)據(jù)在兩個(gè)Socket間通過IO傳輸。
UDP傳輸?shù)氖褂茫?/h3>
1刽锤、DatagramSocket與DatagramPacket
2、建立發(fā)送端朦佩,接收端并思。
3、建立數(shù)據(jù)包语稠。
4宋彼、調(diào)用Socket的發(fā)送接收方法。
5仙畦、關(guān)閉Socket输涕。
發(fā)送端與接收端是兩個(gè)獨(dú)立的運(yùn)行程序
1刽锤、DatagramSocket與DatagramPacket
2、建立發(fā)送端朦佩,接收端并思。
3、建立數(shù)據(jù)包语稠。
4宋彼、調(diào)用Socket的發(fā)送接收方法。
5仙畦、關(guān)閉Socket输涕。
發(fā)送端與接收端是兩個(gè)獨(dú)立的運(yùn)行程序
UDP的使用Demo1:
需求:通過udp傳輸方式,將一段文字?jǐn)?shù)據(jù)發(fā)送出去慨畸。莱坎,
定義一個(gè)udp發(fā)送端。
思路:
1寸士,建立updsocket服務(wù)檐什。
2,提供數(shù)據(jù)弱卡,并將數(shù)據(jù)封裝到數(shù)據(jù)包中乃正。
3,通過socket服務(wù)的發(fā)送功能婶博,將數(shù)據(jù)包發(fā)出去瓮具。
4,關(guān)閉資源凡人。
代碼如下:
class UdpSend {
public static void main(String[] args) throws Exception {
// 1名党,創(chuàng)建udp服務(wù)。通過DatagramSocket對(duì)象挠轴。
DatagramSocket ds = new DatagramSocket(8888);
// 2兑巾,確定數(shù)據(jù),并封裝成數(shù)據(jù)包忠荞。DatagramPacket(byte[] buf, int length, InetAddress
// address, int port)
byte[] buf = "udp ge men lai le ".getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.254"), 10000);
// 3蒋歌,通過socket服務(wù),將已有的數(shù)據(jù)包發(fā)送出去委煤。通過send方法堂油。
ds.send(dp);
// 4,關(guān)閉資源碧绞。
ds.close();
}
}
/*
* 需求: 定義一個(gè)應(yīng)用程序府框,用于接收udp協(xié)議傳輸?shù)臄?shù)據(jù)并處理的。
* 定義udp的接收端讥邻。 思路: 1迫靖,定義udpsocket服務(wù)院峡。通常會(huì)監(jiān)聽一個(gè)端口。其實(shí)就是給這個(gè)接收網(wǎng)絡(luò)應(yīng)用程序定義數(shù)字標(biāo)識(shí)系宜。
* 方便于明確哪些數(shù)據(jù)過來該應(yīng)用程序可以處理照激。
* 2,定義一個(gè)數(shù)據(jù)包盹牧,因?yàn)橐鎯?chǔ)接收到的字節(jié)數(shù)據(jù)俩垃。 因?yàn)閿?shù)據(jù)包對(duì)象中有更多功能可以提取字節(jié)數(shù)據(jù)中的不同數(shù)據(jù)信息。
* 3汰寓,通過socket服務(wù)的receive方法將收到的數(shù)據(jù)存入已定義好的數(shù)據(jù)包中口柳。 4,通過數(shù)據(jù)包對(duì)象的特有功能有滑。將這些不同的數(shù)據(jù)取出跃闹。打印在控制臺(tái)上。
* 5毛好,關(guān)閉資源辣卒。
*/
class UdpRece {
public static void main(String[] args) throws Exception {
// 1,創(chuàng)建udp socket,建立端點(diǎn)睛榄。
DatagramSocket ds = new DatagramSocket(10000);
while (true) {
// 2,定義數(shù)據(jù)包荣茫。用于存儲(chǔ)數(shù)據(jù)。
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
// 3场靴,通過服務(wù)的receive方法將收到數(shù)據(jù)存入數(shù)據(jù)包中啡莉。
ds.receive(dp);// 阻塞式方法。
// 4旨剥,通過數(shù)據(jù)包的方法獲取其中的數(shù)據(jù)咧欣。
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(), 0, dp.getLength());
int port = dp.getPort();
System.out.println(ip + "::" + data + "::" + port);
}
// 5,關(guān)閉資源
// ds.close();
}
}
建議的UDP聊天工具:
/*
* 編寫一個(gè)聊天程序轨帜。 有收數(shù)據(jù)的部分魄咕,和發(fā)數(shù)據(jù)的部分。 這兩部分需要同時(shí)執(zhí)行蚌父。 那就需要用到多線程技術(shù)哮兰。 一個(gè)線程控制收,一個(gè)線程控制發(fā)苟弛。
* 因?yàn)槭蘸桶l(fā)動(dòng)作是不一致的喝滞,所以要定義兩個(gè)run方法。 而且這兩個(gè)方法要封裝到不同的類中膏秫。
*/
import java.io.*;
import java.net.*;
class Send implements Runnable {
private DatagramSocket ds;
public Send(DatagramSocket ds) {
this.ds = ds;
}
public void run() {
try {
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = bufr.readLine()) != null) {
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.255"), 10002);
ds.send(dp);
if ("886".equals(line))
break;
}
} catch (Exception e) {
throw new RuntimeException("發(fā)送端失敗");
}
}
}
class Rece implements Runnable {
private DatagramSocket ds;
public Rece(DatagramSocket ds) {
this.ds = ds;
}
public void run() {
try {
while (true) {
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(), 0, dp.getLength());
if ("886".equals(data)) {
System.out.println(ip + "....離開聊天室");
break;
}
System.out.println(ip + ":" + data);
}
} catch (Exception e) {
throw new RuntimeException("接收端失敗");
}
}
}
class ChatDemo {
public static void main(String[] args) throws Exception {
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receSocket = new DatagramSocket(10002);
new Thread(new Send(sendSocket)).start();
new Thread(new Rece(receSocket)).start();
}
}
TCP的使用
1右遭、Socket和ServerSocket
2、建立客戶端和服務(wù)器端
3、建立連接后窘哈,通過Socket中的IO流進(jìn)行數(shù)據(jù)的傳輸
4吹榴、關(guān)閉socket
同樣,客戶端與服務(wù)器端是兩個(gè)獨(dú)立的應(yīng)用程序滚婉。
TCP鏈接可以用三次握手兩次揮手來形容图筹。
TCP使用Demo1:
/*
* 演示tcp傳輸。
* 1,tcp分客戶端和服務(wù)端满哪。 2婿斥,客戶端對(duì)應(yīng)的對(duì)象是Socket劝篷。 服務(wù)端對(duì)應(yīng)的對(duì)象是ServerSocket哨鸭。
*/
/*
* 客戶端, 通過查閱socket對(duì)象娇妓,發(fā)現(xiàn)在該對(duì)象建立時(shí)像鸡,就可以去連接指定主機(jī)。 因?yàn)閠cp是面向連接的哈恰。所以在建立socket服務(wù)時(shí)只估,
* 就要有服務(wù)端存在,并連接成功着绷。形成通路后蛔钙,在該通道進(jìn)行數(shù)據(jù)的傳輸荠医。
* 需求:給服務(wù)端發(fā)送給一個(gè)文本數(shù)據(jù)吁脱。
* 步驟: 1,創(chuàng)建Socket服務(wù)彬向。并指定要連接的主機(jī)和端口兼贡。
*
*/
import java.io.*;
import java.net.*;
class TcpClient {
public static void main(String[] args) throws Exception {
// 創(chuàng)建客戶端的socket服務(wù)。指定目的主機(jī)和端口
Socket s = new Socket("192.168.1.254", 10003);
// 為了發(fā)送數(shù)據(jù)娃胆,應(yīng)該獲取socket流中的輸出流遍希。
OutputStream out = s.getOutputStream();
out.write("tcp ge men lai le ".getBytes());
s.close();
}
}
/*
* 需求:定義端點(diǎn)接收數(shù)據(jù)并打印在控制臺(tái)上。
* 服務(wù)端: 1里烦,建立服務(wù)端的socket服務(wù)凿蒜。ServerSocket(); 并監(jiān)聽一個(gè)端口。 2胁黑,獲取連接過來的客戶端對(duì)象篙程。
* 通過ServerSokcet的 accept方法。沒有連接就會(huì)等别厘,所以這個(gè)方法阻塞式的虱饿。
* 3,客戶端如果發(fā)過來數(shù)據(jù),那么服務(wù)端要使用對(duì)應(yīng)的客戶端對(duì)象氮发,并獲取到該客戶端對(duì)象的讀取流來讀取發(fā)過來的數(shù)據(jù)渴肉。 并打印在控制臺(tái)。
* 4爽冕,關(guān)閉服務(wù)端仇祭。(可選)
*/
class TcpServer {
public static void main(String[] args) throws Exception {
// 建立服務(wù)端socket服務(wù)。并監(jiān)聽一個(gè)端口颈畸。
ServerSocket ss = new ServerSocket(10003);
// 通過accept方法獲取連接過來的客戶端對(duì)象乌奇。
while (true) {
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + ".....connected");
// 獲取客戶端發(fā)送過來的數(shù)據(jù),那么要使用客戶端對(duì)象的讀取流來讀取數(shù)據(jù)眯娱。
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf, 0, len));
s.close();// 關(guān)閉客戶端.
}
// ss.close();
}
}
TCP使用demo2:
import java.io.*;
import java.net.*;
/*
* 演示tcp的傳輸?shù)目蛻舳撕头?wù)端的互訪礁苗。
* 需求:客戶端給服務(wù)端發(fā)送數(shù)據(jù),服務(wù)端收到后徙缴,給客戶端反饋信息试伙。
*/
/*
* 客戶端: 1,建立socket服務(wù)于样。指定要連接主機(jī)和端口疏叨。 2,獲取socket流中的輸出流穿剖。將數(shù)據(jù)寫到該流中蚤蔓。通過網(wǎng)絡(luò)發(fā)送給服務(wù)端。
* 3糊余,獲取socket流中的輸入流秀又,將服務(wù)端反饋的數(shù)據(jù)獲取到,并打印啄刹。 4涮坐,關(guān)閉客戶端資源。
*
*/
class TcpClient2 {
public static void main(String[] args) throws Exception {
Socket s = new Socket("192.168.1.254", 10004);
OutputStream out = s.getOutputStream();
out.write("服務(wù)端誓军,你好".getBytes());
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf, 0, len));
s.close();
}
}
class TcpServer2 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10004);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "....connected");
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf, 0, len));
OutputStream out = s.getOutputStream();
Thread.sleep(10000);
out.write("哥們收到,你也好".getBytes());
s.close();
ss.close();
}
}
TCP使用Demo3:
/*
* 需求:建立一個(gè)文本轉(zhuǎn)換服務(wù)器袱讹。 客戶端給服務(wù)端發(fā)送文本,服務(wù)單會(huì)將文本轉(zhuǎn)成大寫在返回給客戶端昵时。
* 而且客戶度可以不斷的進(jìn)行文本轉(zhuǎn)換捷雕。當(dāng)客戶端輸入over時(shí),轉(zhuǎn)換結(jié)束壹甥。
* 分析: 客戶端: 既然是操作設(shè)備上的數(shù)據(jù)救巷,那么就可以使用io技術(shù),并按照io的操作規(guī)律來思考句柠。 源:鍵盤錄入浦译。 目的:網(wǎng)絡(luò)設(shè)備棒假,網(wǎng)絡(luò)輸出流。
* 而且操作的是文本數(shù)據(jù)精盅∶毖疲可以選擇字符流。
* 步驟 1叹俏,建立服務(wù)妻枕。 2,獲取鍵盤錄入粘驰。 3屡谐,將數(shù)據(jù)發(fā)給服務(wù)端。 4蝌数,后去服務(wù)端返回的大寫數(shù)據(jù)愕掏。 5,結(jié)束籽前,關(guān)資源亭珍。
* 都是文本數(shù)據(jù)敷钾,可以使用字符流進(jìn)行操作枝哄,同時(shí)提高效率,加入緩沖阻荒。
*/
import java.io.*;
import java.net.*;
class TransClient {
public static void main(String[] args) throws Exception {
Socket s = new Socket("192.168.1.254", 10005);
// 定義讀取鍵盤數(shù)據(jù)的流對(duì)象挠锥。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
// 定義目的,將數(shù)據(jù)寫入到socket輸出流侨赡。發(fā)給服務(wù)端蓖租。
// BufferedWriter bufOut =
// new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
// 定義一個(gè)socket讀取流,讀取服務(wù)端返回的大寫信息羊壹。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while ((line = bufr.readLine()) != null) {
if ("over".equals(line))
break;
out.println(line);
// bufOut.write(line);
// bufOut.newLine();
// bufOut.flush();
String str = bufIn.readLine();
System.out.println("server:" + str);
}
bufr.close();
s.close();
}
}
/*
* 服務(wù)端: 源:socket讀取流蓖宦。 目的:socket輸出流。 都是文本油猫,裝飾稠茂。
*/
class TransServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10005);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "....connected");
// 讀取socket讀取流中的數(shù)據(jù)沫浆。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
// 目的哄辣。socket輸出流。將大寫數(shù)據(jù)寫入到socket輸出流窑滞,并發(fā)送給客戶端毡证。
// BufferedWriter bufOut =
// new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
String line = null;
while ((line = bufIn.readLine()) != null) {
System.out.println(line);
out.println(line.toUpperCase());
// bufOut.write(line.toUpperCase());
// bufOut.newLine();
// bufOut.flush();
}
s.close();
ss.close();
}
}
TCP使用Demo4电爹,上傳文本:
import java.io.*;
import java.net.*;
class TextClient {
public static void main(String[] args) throws Exception {
Socket s = new Socket("192.168.1.254", 10006);
BufferedReader bufr = new BufferedReader(new FileReader("IPDemo.java"));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
String line = null;
while ((line = bufr.readLine()) != null) {
out.println(line);
}
s.shutdownOutput();// 關(guān)閉客戶端的輸出流。相當(dāng)于給流中加入一個(gè)結(jié)束標(biāo)記-1.
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = bufIn.readLine();
System.out.println(str);
bufr.close();
s.close();
}
}
class TextServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10006);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "....connected");
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter(new FileWriter("server.txt"), true);
String line = null;
while ((line = bufIn.readLine()) != null) {
// if("over".equals(line))
// break;
out.println(line);
}
PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
pw.println("上傳成功");
out.close();
s.close();
ss.close();
}
}
TCP使用之上傳圖片
/*
* 需求:上傳圖片料睛。
*/
/*
* 客戶端丐箩。
* 1摇邦,服務(wù)端點(diǎn)。
* 2屎勘,讀取客戶端已有的圖片數(shù)據(jù)涎嚼。
* 3,通過socket 輸出流將數(shù)據(jù)發(fā)給服務(wù)端挑秉。
* 4法梯,讀取服務(wù)端反饋信息。
* 5犀概,關(guān)閉立哑。
*/
import java.io.*;
import java.net.*;
class PicClient {
public static void main(String[] args) throws Exception {
Socket s = new Socket("192.168.1.254", 10007);
FileInputStream fis = new FileInputStream("c:\\1.bmp");
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
// 告訴服務(wù)端數(shù)據(jù)已寫完
s.shutdownOutput();
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int num = in.read(bufIn);
System.out.println(new String(bufIn, 0, num));
fis.close();
s.close();
}
}
/*
* 服務(wù)端
*/
class PicServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10007);
Socket s = ss.accept();
InputStream in = s.getInputStream();
FileOutputStream fos = new FileOutputStream("server.bmp");
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
}
OutputStream out = s.getOutputStream();
out.write("上傳成功".getBytes());
fos.close();
s.close();
ss.close();
}
}
TCP之多線程上傳圖片
/*
* 需求:上傳圖片。
*/
/*
* 客戶端姻灶。
* 1铛绰,服務(wù)端點(diǎn)。
* 2产喉,讀取客戶端已有的圖片數(shù)據(jù)捂掰。
* 3,通過socket 輸出流將數(shù)據(jù)發(fā)給服務(wù)端曾沈。
* 4这嚣,讀取服務(wù)端反饋信息。
* 5塞俱,關(guān)閉姐帚。
*
*/
import java.io.*;
import java.net.*;
class PicClient {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.out.println("請(qǐng)選擇一個(gè)jpg格式的圖片");
return;
}
File file = new File(args[0]);
if (!(file.exists() && file.isFile())) {
System.out.println("該文件有問題,要么補(bǔ)存在障涯,要么不是文件");
return;
}
if (!file.getName().endsWith(".jpg")) {
System.out.println("圖片格式錯(cuò)誤,請(qǐng)重新選擇");
return;
}
if (file.length() > 1024 * 1024 * 5) {
System.out.println("文件過大罐旗,沒安好心");
return;
}
Socket s = new Socket("192.168.1.254", 10007);
FileInputStream fis = new FileInputStream(file);
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
// 告訴服務(wù)端數(shù)據(jù)已寫完
s.shutdownOutput();
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int num = in.read(bufIn);
System.out.println(new String(bufIn, 0, num));
fis.close();
s.close();
}
}
/*
* 服務(wù)端
*
* 這個(gè)服務(wù)端有個(gè)局限性。當(dāng)A客戶端連接上以后唯蝶。被服務(wù)端獲取到九秀。服務(wù)端執(zhí)行具體流程。 這時(shí)B客戶端連接粘我,只有等待鼓蜒。
* 因?yàn)榉?wù)端還沒有處理完A客戶端的請(qǐng)求,還有循環(huán)回來執(zhí)行下次accept方法涂滴。所以 暫時(shí)獲取不到B客戶端對(duì)象友酱。
* 那么為了可以讓多個(gè)客戶端同時(shí)并發(fā)訪問服務(wù)端。 那么服務(wù)端最好就是將每個(gè)客戶端封裝到一個(gè)單獨(dú)的線程中柔纵,這樣缔杉,就可以同時(shí)處理多個(gè)客戶端請(qǐng)求。
* 如何定義線程呢搁料?
*
* 只要明確了每一個(gè)客戶端要在服務(wù)端執(zhí)行的代碼即可或详。將該代碼存入run方法中系羞。
*/
class PicThread implements Runnable {
private Socket s;
PicThread(Socket s) {
this.s = s;
}
public void run() {
int count = 1;
String ip = s.getInetAddress().getHostAddress();
try {
System.out.println(ip + "....connected");
InputStream in = s.getInputStream();
File dir = new File("d:\\pic");
File file = new File(dir, ip + "(" + (count) + ")" + ".jpg");
while (file.exists())
file = new File(dir, ip + "(" + (count++) + ")" + ".jpg");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
}
OutputStream out = s.getOutputStream();
out.write("上傳成功".getBytes());
fos.close();
s.close();
} catch (Exception e) {
throw new RuntimeException(ip + "上傳失敗");
}
}
}
class PicServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10007);
while (true) {
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
// ss.close();
}
}
TCP使用之并發(fā)登陸
/*
* 客戶端通過鍵盤錄入用戶名。 服務(wù)端對(duì)這個(gè)用戶名進(jìn)行校驗(yàn)霸琴。
* 如果該用戶存在椒振,在服務(wù)端顯示xxx,已登陸梧乘。 并在客戶端顯示 xxx澎迎,歡迎光臨。
* 如果該用戶存在选调,在服務(wù)端顯示xxx夹供,嘗試登陸。 并在客戶端顯示 xxx仁堪,該用戶不存在哮洽。
* 最多就登錄三次。
*/
import java.io.*;
import java.net.*;
class LoginClient {
public static void main(String[] args) throws Exception {
Socket s = new Socket("192.168.1.254", 10008);
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
for (int x = 0; x < 3; x++) {
String line = bufr.readLine();
if (line == null)
break;
out.println(line);
String info = bufIn.readLine();
System.out.println("info:" + info);
if (info.contains("歡迎"))
break;
}
bufr.close();
s.close();
}
}
class UserThread implements Runnable {
private Socket s;
UserThread(Socket s) {
this.s = s;
}
public void run() {
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "....connected");
try {
for (int x = 0; x < 3; x++) {
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String name = bufIn.readLine();
if (name == null)
break;
BufferedReader bufr = new BufferedReader(new FileReader("user.txt"));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
String line = null;
boolean flag = false;
while ((line = bufr.readLine()) != null) {
if (line.equals(name)) {
flag = true;
break;
}
}
if (flag) {
System.out.println(name + ",已登錄");
out.println(name + ",歡迎光臨");
break;
} else {
System.out.println(name + ",嘗試登錄");
out.println(name + ",用戶名不存在");
}
}
s.close();
} catch (Exception e) {
throw new RuntimeException(ip + "校驗(yàn)失敗");
}
}
}
class LoginServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10008);
while (true) {
Socket s = ss.accept();
new Thread(new UserThread(s)).start();
}
}
}