例子1:客户端发送信息给服务端,服务端将数据显示在控制台上
建立两个单元测试方法,用Client充当客户端,Server充当服务端
因为是发给服务器端,所以要知道服务器端是哪个IP,是哪个端口号,都需要指明
又因为IP和端口号封装为Socket
在客户端创建一个Socket,里面包含具体的IP和端口号
形象理解;
有两个岛,一个叫客户端岛,一个叫服务器岛,客户端岛想把自己生产的产品运到服务器岛,装产品的小船就相当于是Socket,需要知道是哪个岛,所以要知道IP,知道运往哪个岛之后,还要知道运到哪个港口,就相当于要知道端口号,在港口有ServerSocket用来接受Socket,接受到以后,就用输入流获取Socket中的数据,最后在把通道关闭
public class test {
//要先启动服务器,如果先启动客户端,就去建立连接了,然后会发现服务器端没有启动
//可以自己连接自己
@Test
public void client(){
//一定要用try-catch的方式处理异常
Socket socket= null;
OutputStream os = null;
try {
//1.创建Socket对象,指明服务器端的IP和端口号
InetAddress inet = InetAddress.getByName("127.0.0.1");//指明Server的IP,又因为反正也是本地,就用127.0.0.1
socket = new Socket(inet,8899);
//2.获取输出流,用于输出数据
//有了Socket之后,Socket要来传输数据
os = socket.getOutputStream();
//3.写出数据
os.write("你好,我是客户端".getBytes());//就发出去了,服务器端就要接受
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源的关闭
//Socket也是资源,类似于流一样,发送完数据以后要关闭资源
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//Alt+shift+z 用try-catch-finally
@Test
public void server(){
ServerSocket ss = null;//用来接受数据,指明自己的端口号即可,是先有这里的8899,才有客户端的8899
Socket socket = null;//用来接受客户端的socket
InputStream is = null;
ByteArrayOutputStream baos= null;//没有像IO流那样指定文件
try {
//1.创建服务器端的ServerSocket,指明自己的端口号,在哪个主机上跑的IP就是多少,没有必要指明IP
ss = new ServerSocket(8899);
//2.调用accept方法,接收来自客户端的Socket
socket = ss.accept();
//3.获取输入流
//因为现在要读入,所以使用Input
is = socket.getInputStream();
//把流中的数据显示到控制台上
//不建议这样写,可能有乱码
// byte[] bytes=new byte[20];
// int len;
// while((len=is.read(bytes))!=-1){
// String str=new String(bytes,0,len);
// System.out.println(str);
// }
//上面这种写法其实有问题,InputStream是字节流,我们写的有中文,如果是UTF-8,一个字就占3个字节,所以把byte数组开的大一点
//如果是new byte[5],那么好这个字就被劈成两半了,还原成String就出问题了
//开比较大比如1024不能完全解决问题,不建议这么做
//最好这么做,利用 ByteArrayOutputStream
//4.读取输入流当中的数据
baos = new ByteArrayOutputStream();
//数据写到ByteArrayOutputStream中的一个数组里,不够会扩容,分是分两半了,但又拼起来了,并没有独立的还原成字符串,最后输入完成之后,整体转化成字符串
byte[] bytes=new byte[5];//造多短都无所谓
int len;
while((len=is.read(bytes))!=-1){
baos.write(bytes,0,len);//从bytes中把数据取出来,写到数组中
}
//把数据输出到控制台上
System.out.println(baos.toString());//不会出现乱码,把内部的字节数组转化成字符串
System.out.println("收到了来自于"+socket.getInetAddress().getHostAddress()+"的数据");//收到了来自于127.0.0.1的数据,用来得出是谁给服务器端发送的,获取它的IP,想看地址再用getHostAddress
} catch (IOException e) {
e.printStackTrace();
} finally {
//输出完以后,要关闭资源,baos是流,要关掉
//资源的关闭
if(baos!=null){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(ss!=null){
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
例子2:
客户端发送文件给服务端,服务端将文件保存在本地。
public class test {
@Test
public void client(){
Socket socket= null;
OutputStream os = null;
FileInputStream fis= null;
try {
socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
os = socket.getOutputStream();
//如果想让效率高一点可以用缓冲流包一下
fis = new FileInputStream(new File("fun.jpg"));
byte[] bytes=new byte[1024];
int len;
while((len=fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void Server(){
ServerSocket ss = null;
Socket socket = null;
InputStream is = null;
FileOutputStream fos= null;
try {
ss = new ServerSocket(9090);
socket = ss.accept();
is = socket.getInputStream();
//保存在本地的文件当中
fos = new FileOutputStream("beauty.jpg");
byte[] bytes=new byte[1024];
int len;
while((len=is.read(bytes))!=-1){
fos.write(bytes,0,len);//写到"beauty.jpg"这个文件中了
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(ss!=null){
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
例题3:
从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端(所以说客户端发送完成之后不要着急关闭(close))。客户端把反馈信息显示到控制台上,并关闭相应的连接。
问题代码:
public class test {
@Test
public void client(){
Socket socket= null;
OutputStream os = null;
FileInputStream fis= null;
InputStream is =null;
try {
socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
os = socket.getOutputStream();
//如果想让效率高一点可以用缓冲流包一下
fis = new FileInputStream(new File("fun.jpg"));
byte[] bytes=new byte[1024];
int len;
while((len=fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
//接收来自服务器端的信息并显示到控制台上
is = socket.getInputStream();
byte[] bytes1=new byte[20];
//ByteArrayOutputStream
ByteArrayOutputStream baos=new ByteArrayOutputStream();
int len1;
while((len1=is.read(bytes1))!=-1){
baos.write(bytes1,0,len1);
}
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void Server(){
ServerSocket ss = null;
Socket socket = null;
InputStream is = null;
FileOutputStream fos= null;
OutputStream os=null;
try {
ss = new ServerSocket(9090);
socket = ss.accept();
is = socket.getInputStream();
//保存在本地的文件当中
fos = new FileOutputStream("beauty1.jpg");
byte[] bytes=new byte[1024];
int len;
while((len=is.read(bytes))!=-1){
fos.write(bytes,0,len);//写到"beauty.jpg"这个文件中了
}
//服务器端给予客户端反馈,因为要往外面写数据,所以要用getOutputStream
os = socket.getOutputStream();
os.write("照片已收到".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(ss!=null){
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Server中接受图片数据的read方法,这个方法是一个阻塞式的方法,意思就是如果没有明确指示就不会退出循环,Cilent在传输图片数据的时候并没有给出明确的指示表明数据已经传完了,Server就会一直等着客户端接着发数据,会始终停留在接受图片数据的while循环当中,不能执行下面的后续操作,导致没有输出信息,两个都没有关闭
在客户端把图片传完以后要给出明确的指示
NIO就是非阻塞式的
正解:加上socket.shutdownOutput();关闭数据的输出
@Test
public void client(){
Socket socket= null;
OutputStream os = null;
FileInputStream fis= null;
InputStream is =null;
try {
socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
os = socket.getOutputStream();
//如果想让效率高一点可以用缓冲流包一下
fis = new FileInputStream(new File("fun.jpg"));
byte[] bytes=new byte[1024];
int len;
while((len=fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
//关闭数据的输出
socket.shutdownOutput();
//接收来自服务器端的信息并显示到控制台上
is = socket.getInputStream();
byte[] bytes1=new byte[20];
//ByteArrayOutputStream
ByteArrayOutputStream baos=new ByteArrayOutputStream();
int len1;
while((len1=is.read(bytes1))!=-1){
baos.write(bytes1,0,len1);
}
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}