——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
简介
UDP分为发送端和接受端
TCP分为客户端和服务器端(Socket和ServerSocket)
建立连接后
TCP三次握手的过程如下:
客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。
服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。
客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。
三次握手完成,TCP客户端和服务器端成功地建立连接,可以开始传输数据了。
下面演示TCP传输的客户端和服务器端的互访
客户端发送数据给服务器端,服务器端接受数据后给客户端反馈信息
服务器端
package fourth;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
*服务器端:
*1.创建服务器端的Socket服务,ServerSocket,并监听一个端口
*2.获取连接过来的客户端对象,通过ServerSocket的accept完成,这个方法是阻塞式的,如果没有连接就等待
*3.客户端如果发送过来数据,那么服务器端要使用对应的客户端对象,并获取到该客户端对象的读取流来获取数据
*4.关闭服务器(可选操作)
*
*定义服务器端,接受数据并打印在控制台上
*/
public class TcpServer2 {
public static void main(String[] args) {
try {
//建立服务端的Socket服务,并监听一个端口
ServerSocket ss=new ServerSocket(10004);
//通过accept获取客户端的发送数据
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+".....connected");
//获取数据
InputStream is=s.getInputStream();
OutputStream out=s.getOutputStream();
byte[]b=new byte[1024];
int len=is.read(b);
System.out.println(new String(b,0,len));
out.write("收到了,".getBytes());
s.close();//结束连接
ss.close();//可选的
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端
package fourth;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
*客户端:
*给服务器端发送一个文本数据
*1.创建Socket服务,并指定要连接的主机和端口
*2.获取Socket服务中的输出流,将数据写到流中,通过网络发送给服务器
*3.获取Socket服务中的输入流,获取服务器的反馈数据并打印
*4,关闭资源
*
*/
public class TcpClient2 {
public static void main(String[] args) {
try {
//创建Socket服务,并指定要连接的主机和端口
Socket s=new Socket(InetAddress.getLocalHost(), 10004);
//为了发送数据,应该获得Socket流中的输出流
OutputStream out=s.getOutputStream();
out.write("Hello TCPClient".getBytes());
InputStream is=s.getInputStream();
byte[]b=new byte[1024];
int len=is.read(b);
System.out.println(new String(b,0,len));
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注:一定要先启动服务器端,不然先启动客户端会报java.net.ConnectException异常
下面这个练习实现了服务器端的文本转换功能,把客户端的文本数据转成大写在返回
服务器端
package fourth;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
*需求:建立一个文本转换服务器
*客户端给服务器端发送文本,服务器端把文本转换为大写返回给客户端
*而且客户端可以不断进行文本转换,当客户端输入over时结束
*
*分析
*客户端:
*既然是在设备上操作数据,就可以用IO技术,并按照IO的操作规则来思考
*源:键盘录入
*目的:网络设备,网络输出流
*操作的是文本数据,可以使用字节流,同时提高效率加入缓冲
*服务器端
*源:Socket读取流
*目的:Socket输出流
*都是文本,
*/
public class TransServer {
public static void main(String[] args) {
try {
ServerSocket ss=new ServerSocket(10005);
Socket s=ss.accept();
//读取Socket流中的数据
BufferedReader brIn=new BufferedReader(
new InputStreamReader(s.getInputStream()));
//目的,Socket输出流,将大写数据写入到Socket输出流发送给客户端
// BufferedWriter bwOut=new BufferedWriter(
// new OutputStreamWriter(s.getOutputStream()));
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
String line=null;
while((line=brIn.readLine())!=null){
// bwOut.write(line.toUpperCase());
// bwOut.newLine();
// bwOut.flush();
out.println(line);
}
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端
package fourth;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
*
*步骤
*1.建立服务
*2.获取键盘录入
*3.将数据发给服务器端
*4.获取服务器端返回数据,打印到控制台
*5,关闭资源
*
*/
public class TransClient {
public static void main(String[] args) {
try {
Socket s=new Socket(InetAddress.getLocalHost(), 10005);
//获取键盘数据
BufferedReader br=
new BufferedReader(new InputStreamReader(System.in));
//定义目的,将数据写入Socket流发给服务器端
// BufferedWriter bwOut=new BufferedWriter(
// new OutputStreamWriter(s.getOutputStream()));
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
//定义一个Socket读取流,读取服务器端返回信息
BufferedReader brIn=new BufferedReader(
new InputStreamReader(s.getInputStream()));
String line=null;
while((line=br.readLine())!=null){
if("over".equals(line))
break;
// bwOut.write(line);
// bwOut.newLine();
// bwOut.flush();
out.println(line);
System.out.println("server :: "+brIn.readLine());
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注:上边两个程序有几行被注释了,那是被下边一行代码给替换了,它们都能成功
可能出现的问题,客户端和服务器端都在莫名的等待,这事因为它们都有阻塞式方法,可能的原因是这个方法没有读到结束标记,就一直在等
即bwOut.newLine();bwOut.flush();这两句代码被忽略是会出现这种情况
下面写一个上传文件的程序
服务器端
package fourth;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TextServer {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(10006);
Socket s=ss.accept();
BufferedReader brIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter pw=new PrintWriter(new FileWriter("D:\\info.txt"));
String line=null;
while((line=brIn.readLine())!=null){
if (line.equals("over")) {
break;
}
pw.println(line);
}
PrintWriter out=new PrintWriter(s.getOutputStream());
out.println("上传成功");
out.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端
package fourth;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class TextClient {
public static void main(String[] args) {
try {
Socket s = new Socket(InetAddress.getLocalHost(),10006);
BufferedReader br =new BufferedReader(new FileReader("E:\\info.txt"));
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
String line=null;
while((line=br.readLine())!=null){
out.println(line);
}
s.shutdownOutput();//关闭客户端输出流,相当于加入结束标记
BufferedReader brIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
System.out.println(brIn.readLine());
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
over,主要注意s.shutdownOutput();结束标记