基于Socket的TCP编程
Java语言的基于套接字编程分为服务端编程和客户端编程,其通信模型如图所示:
从客户端来说
客户端Socket的工作过程包含以下四个基本的步骤:
- 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
- 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用getOutputStream()方法获得输出流,进行数据传输
- 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程。
- 关闭 Socket:断开客户端到服务器的连接,释放线路
客户端创建Socket对象:
客户端程序可以使用Socket类创建对象,创建的同时会自动向服务器方发起连接,Socket的构造器是:
- Socket(String host,int port)throws UnknownHostException,IOException:向服务器(域名是host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。
- Socket(InetAddress address,int port)throws IOException:根据InetAddress对象所表示的IP地址以及端口号port发起连接。
从服务器来说
服务器程序的工作过程包含以下四个基本的步骤:
- 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。
- 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
- 调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出流和输入流,开始网络数据的发送和接收。
- 关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。
服务器建立 ServerSocket 对象:
ServerSocket 对象负责等待客户端请求建立套接字连接,类似邮局某个窗口中的业务员。也就是说,服务器必须事先建立一个等待客户请求建立套接字连接的ServerSocket对象。
所谓“接收”客户的套接字请求,就是accept()方法会返回一个 Socket 对象
关于Socket的理解
这个我参考了其他博主的文章,我觉得写的非常清晰:
TCP网络编程例题
例题一
要求:客户端发送信息给服务端,服务端将数据显示在控制台上
代码实现:
//此为客户端
@Test
public void client() {
Socket kehu = null;
OutputStream words = null;
try {
//首先创建Socket(这个是指向服务器的)
kehu = new Socket("127.0.0.1",8989);
//开始传输信息
words = kehu.getOutputStream();
words.write("这里是客户端".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
}
//关闭流(使用try-catch)
if(words != null){
try {
words.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(kehu != null){
try {
kehu.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//此为服务端
@Test
public void server(){
ServerSocket receiver = null;
Socket receive = null;
InputStream shuru = null;
ByteArrayOutputStream box = null;
try {
//首先创建ServerSocket对相应端口进行监听
receiver = new ServerSocket(8989);
// 接收来自客户端的Socket
receive = receiver.accept();
//以此Socket创建输入流
shuru = receive.getInputStream();
//用ByteArrayOutputStream来接收,不建议使用byte型数组装然后再转为字符串,因为装满的时候
//正好有个字符的字节缺失
box = new ByteArrayOutputStream();
int len;
byte[] box1 = new byte[10];
while((len = shuru.read(box1)) != -1){
box.write(box1,0,len);
}
//将ByteArrayOutputStream缓冲区中的字节直接转化为字符串输出到控制台中
System.out.println(box.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
}
//关闭流
if(box != null){
try {
box.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (shuru != null){
try {
shuru.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(receive != null){
try {
receive.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(receiver != null){
try {
receiver.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注:①在服务器端不建议使用
//不建议这样写,可能会有乱码
// byte[] buffer = new byte[1024];
// int len;
// while((len = is.read(buffer)) != -1){
// String str = new String(buffer,0,len);
// System.out.print(str);
// }
②在服务器端使用了ByteArrayOutputStream的缓冲区去接收,而不是ByteArrayInputStream。
例题二
任务:客户端发送文件给服务端,服务端将文件保存在本地。
代码实现:
/*
这里涉及到的异常,应该使用try-catch-finally处理
*/
@Test
public void client() throws IOException {
//1.
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
//2.
OutputStream os = socket.getOutputStream();
//3.
FileInputStream fis = new FileInputStream(new File("beauty.jpg"));
//4.
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
os.write(buffer,0,len);
}
//5.
fis.close();
os.close();
socket.close();
}
/*
这里涉及到的异常,应该使用try-catch-finally处理
*/
@Test
public void server() throws IOException {
//1.
ServerSocket ss = new ServerSocket(9090);
//2.
Socket socket = ss.accept();
//3.
InputStream is = socket.getInputStream();
//4.
FileOutputStream fos = new FileOutputStream(new File("beauty1.jpg"));
//5.
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
//6.
fos.close();
is.close();
socket.close();
ss.close();
}
例题三
任务:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端。
代码实现:
/*
这里涉及到的异常,应该使用try-catch-finally处理
*/
@Test
public void client() throws IOException {
//1.
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
//2.
OutputStream os = socket.getOutputStream();
//3.
FileInputStream fis = new FileInputStream(new File("beauty.jpg"));
//4.
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
os.write(buffer,0,len);
}
//关闭数据的输出
socket.shutdownOutput();
//5.接收来自于服务器端的数据,并显示到控制台上
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[20];
int len1;
while((len1 = is.read(buffer)) != -1){
baos.write(buffer,0,len1);
}
System.out.println(baos.toString());
//6.
fis.close();
os.close();
socket.close();
baos.close();
}
/*
这里涉及到的异常,应该使用try-catch-finally处理
*/
@Test
public void server() throws IOException {
//1.
ServerSocket ss = new ServerSocket(9090);
//2.
Socket socket = ss.accept();
//3.
InputStream is = socket.getInputStream();
//4.
FileOutputStream fos = new FileOutputStream(new File("beauty2.jpg"));
//5.
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
System.out.println("图片传输完成");
//6.服务器端给予客户端反馈
OutputStream os = socket.getOutputStream();
os.write("你好,照片我已收到".getBytes());
//7.
fos.close();
is.close();
socket.close();
ss.close();
os.close();
}
注意:客户端传完图片之后一定要关闭数据的输出(shutdownOutput()),如果不手动关闭,因为服务端接收时的read()方法是一种阻塞式的方法,他会一直等到客户端传输结束,但是这个信号一直没有来,他就会一直等。((len = is.read(buffer)) != -1并不能阻止这个情况的发生,因为read返回-1是代表到达流的末尾,而此时read是不能确定是否到达了流的末尾的,所以他才一直等)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/122316.html