您的位置:首页 > 理论基础 > 计算机网络

javase_22(TCP的学习-->)

2012-09-04 23:22 399 查看
TCP传输

Socket(客户端)和ServerSocket(服务端)

1.建立客户端和服务器端

2.建立连接后,通过Socket中的IO流进行数据的传输

3.关闭Socket()当关闭这个流,其实就是把底层的流所关闭

同样,客户端与服务器端程序是两个独立运行的应用程序.

基本思路:(客户端)

客户端需要明确服务器的IP地址和端口,这样才可以试图去建立连接.如果连接失败,会出现异常.

连接成功,说明客户端与服务器端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通过

getInputStream(), getOutputStream()获取即可.

与服务端通信结束,关闭Socket.

基本思路:(服务器端)

服务端需要明确它要处理的数据是从那个端口进入的.

当有客户端访问时,要明确是那个客户端,可通过accept()获取已经连接的客户端对象,并且通过该对象与客户端通过IO流进行数据的传输.

当客户端访问结束,关闭该客户端.

生动的比喻:

必须要建立114服务台,客户才可以拨打的道理..当TCP服务器程序运行到ServerSocket.accept方法等待客户的连接,在正常的情况下,accept方法会发生阻塞,一直等到客户连接请求的到来.该方法才会返回.如果没有客户端请求来的情况下,accept方法没有发生阻塞,那么肯定前面的程序是有问题的.,通常端口被其他的程序所占用.

利用循环从客户端里面读取数据,并且在服务端显示出来?不要把问题那么复杂,该多线程就多线程-->该怎么走.比喻用到多线程.-->休息一下.等待它读取数据.要不然.我都还没有读取数据.-->你这边就已经执行了.

客户端

通过Socket建立对象并指定要连接的服务端主机与端口

Socket s = new Sockte("127.0.0.0.1",8888);
InputStream ips = s.getInputS	tream();
OutputStream ops = s.getOutputStream();
S.close();//底层的流必须要关闭/.


服务端:

建立服务端需要监听的一个端口:

ServerSocket ss = new ServerSocket(8888);
//获取到客户端的Socket .
Socket ss = Ss.accept();
InputStream ips = s.getInputStream();
OutputStream ops = s.getOutputStream();
byte [] buf = new byte[1024];
Ips.read(buf);
int num = ips.read(buf);
String str = new String(buf,0,num);
Ss.close();
S.close();


简单的TCP客户端与服务端:

客户端:

package com.javami.kudyDemo.Tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TcpClient
{

/**
* 客户端
*/
public static void main(String[] args)
{
Socket socket = null;
try
{
//连接到指定的主机端口号上
socket = new Socket("127.0.0.1",8888);

//-->读取服务端的数据
InputStream ips = socket.getInputStream();
//-->发送服务端的数据
OutputStream ops = socket.getOutputStream();
ops.write("服务器你最近还好吗?".getBytes());//转换成字节流
ops.write("可以同时写两个数据吗??".getBytes());//转换成字节流
byte [] buf = new byte[ips.available()];
ips.read(buf);
System.out.println(new String(buf));
}
catch(IOException e)
{

}finally
{
try
{
if(socket!=null)
socket.close();
}catch(IOException e)
{
e.printStackTrace();
}
}

}

}


服务端:

package com.javami.kudyDemo.Tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer
{
/*
* 服务端
*/
public static void main(String[]args)
{
ServerSocket ss = null;;
Socket socket = null;
try
{
ss = new ServerSocket(8888);
socket = ss.accept();//监听端口--->和客户端已经绑定起来
InputStream ips = socket.getInputStream();
OutputStream ops = socket.getOutputStream();
byte[] buf = new byte[ips.available()];//个数为多少
ips.read(buf);
System.out.println(new String(buf));
ops.write("我最近过得还好~你不需要担心我服务器的寿命".getBytes());
}catch(IOException e)
{

一个程序开启了多线程-->Thread-0线程去执行..-->Main线程也在执行的.

必须让main线程等待一下.让其有一个消化的过程.

字母的转换:(使用了多线程解决问题)

客户端类

package com.javami.kudyDemo.Tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class ReverseClinet
{
public static void main(String[]args) throws InterruptedException, UnknownHostException, IOException
{
Socket socket = null;
socket = new Socket("127.0.0.1",8888);
InputStream ips = socket.getInputStream();
OutputStream ops = socket.getOutputStream();
//接收欢迎语,必须要先休息一下.因为那边写入数据.如果不休息.
//由于是开了线程执行的.main主线程就打印出来.所以打印到你的内容必定是空白的
Thread.sleep(10);
int len = ips.available();
byte[] buf = new byte[len];
ips.read(buf);
System.out.println(new String(buf));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("开始吧!!");
while(true)
{
String line = br.readLine();
ops.write((line+"\r\n").getBytes());//写入进去
int l = ips.available();
byte[] b = new byte[l];
Thread.sleep(10);
ips.read(b);
System.out.println(new String(b));
}
}
}


服务端:

package com.javami.kudyDemo.Tcp;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/*
* 服务器提供字符反向服务
*多线程的思路:
*我等待用户的连接..当有用户连接.我交给别的线程去执行.对象是仍然没有变.-->socket重点.
*必须要循环监听.如果不循环监听...当一个服务端和客户端再运行..我就结束了..
*/
public class ReverseServer
{
public static void main(String[]args)
{
ServerSocket ss = null;
try
{
ss = new ServerSocket(8888);
while(true)
{
Socket socket = ss.accept();
new Thread(new ReverseServers(socket)).start();
}
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}finally
{
if(ss!=null)
try
{
ss.close();
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

-->它的哥们
package com.javami.kudyDemo.Tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class ReverseServers implements Runnable
{
Socket socket ;
public  ReverseServers(Socket socket)
{
this.socket = socket;
}
public  void run()
{
try
{
InputStream ips = socket.getInputStream();
OutputStream ops = socket.getOutputStream();
ops.write("启动服务器提供反转功能:".getBytes());
while(true)
{
BufferedReader br =
new BufferedReader(new InputStreamReader(ips));//把读取到的数据转换成字符流
String line = br.readLine();
if("quit".equals(line))
break;
StringBuilder sb = new StringBuilder(line);
String newLine = sb.reverse().toString();//转换
ops.write(newLine.getBytes());
}
}catch(IOException e)
{
e.printStackTrace();
}finally
{
if(socket!=null)
try
{
socket.close();
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}


TCP网络程序的工作原理:

TCP客户端程序与TCP服务端程序的交互过程:

1.服务器端程序创建一个ServerSocket,然后调用accpept方法等待客户来连接.

2.客户端程序创建一个Socket并请求服务端建立连接.

3.服务器端接收客户的连接请求,并创建一个新的Socket与该客户建立专线连接.

4.建立了连接的两个Socket在一个单独的线程(由服务端程序创建)上对话.

5.服务器端开始等待i新的连接请求,当新的连接请求到达时,重复上述过程.

文件上传案例分析

一、需求分析

1.多线程的服务器

2.客户端程序

3.上传文件名

4.上传文件

二、实现步骤

1.实现多线程服务器

1)创建ServerSocket对象,监听指定的端口,7888

2)循环调用accept方法,等待客户端的连接,次方法阻塞,返回一个客户端Socket

3)开启新线程,运行一个服务对象,将socket给这个对象

2.实现客户端程序

1)创建Socket对象,连接服务器 127.0.0.1 7888

3.发送和接收欢迎语

服务器端: 获得输入输出流, 发送欢迎语, out.write();

客户端: 获得输入输出流, 接收欢迎语, in.read();

4.发送文件名,创建文件

1)客户端:

读键盘,获得文件路径名 BufferedReader

创建文件对象, File

判断文件是否存在,文件是否为标准文件 isFile

获得文件名:getName

将文件名上传给服务器,out.write

等待接收服务器反馈的信息

2)服务器端:

接收文件名,in.read();

创建文件对象, 在指定目录下创建 createNewFile

判断是否创建成功,文件已存在或创建失败, 将是否可以继续上传的信息发给客户端 out.write

5.上传文件

1)客户端:

如果可以开始上传文件了

BufferedInputStream包装FileInputStream

BufferedOutputStream包装 socket.getOutputStream()

实现流的对拷,逐个字节拷贝,

2)服务器端

接收客户端上传的数据写入新创建的文件中

BufferedInputStream包装socket.getInputStream()

BufferedOutputStream包装 FileOutputStream

实现流的对拷,逐个字节拷贝。

文件的上传功能小项目

客户端:
package com.javami.kudyDemo;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class UploadClient
{

public static void main(String[] args)
{
Socket socket = null;
try
{
socket = new Socket("127.0.0.1",8888);
InputStream ips = socket.getInputStream();
OutputStream ops = socket.getOutputStream();
//接收欢迎语句
Thread.sleep(10);//-->等待线程的写入
int len = ips.available();
byte[] buf = new byte[len];
ips.read(buf);
System.out.println(new String(buf));

//上传文件名
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入你的文件名:");
File file = null;
while(true)
{
String fileName = br.readLine();
if("quit".equals(fileName))
return ;
file = new File(fileName);
if(file.isFile())
{
ops.write(file.getName().getBytes());
break;//如果是文件--写入进去
}
if(!file.isFile())
System.out.println("该文件不存在,请重新输入");
else
System.out.println("只支持标准文件的上传");
}

//等待服务端的反馈:
buf = new byte[1024];
len = ips.read(buf);
String info = new String(buf,0,len);
System.out.println(info);
if(!"可以上传文件".equals(info))
return;
long fileSize = file.length();
ops.write(String.valueOf(fileSize).getBytes());
Thread.sleep(100);

//上传文件
upload(file,ops);

//等待服务端的反馈
len = ips.read(buf);
System.out.println(new String(buf,0,len));
}catch(Exception  e)
{
e.printStackTrace();
}finally
{

}
}

private static void upload(File file, OutputStream ops) throws IOException
{
BufferedInputStream bis =
new BufferedInputStream(new FileInputStream(file));//读取林的内容
BufferedOutputStream bos = new BufferedOutputStream(ops);//写入内容
System.out.println("文件上传中~~~~");
int ch ;
while((ch=bis.read())!=-1)
{
bos.write(ch);
}
bos.flush();//这个刷新一下就可以.因为让底层去关.要不然就会发生冲突
bis.close();//这个必须要关
}

}
服务端:
package com.javami.kudyDemo;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class UploadServer
{
/*
* 必须要用到多线程去做.如果你没有使用多线程..那么main线程只能和一个连接打交道..
* while
*
*/
public static void main(String[]args)
{
ServerSocket ss = null;
try
{
System.out.println("服务器已经开启,正在监听8888端口");
ss = new ServerSocket(8888);
while(true)//我while循环没有结束-->在监听啦~~~
{
Socket socket = ss.accept();//当每一个线程都进来的时候,这里会发生阻塞
System.out.println("成功与一个客户端建立连接"+
socket.getInetAddress().getHostAddress());
new Thread(new UploadServers(socket)).start();
}
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}finally
{
if(ss!=null)
try
{
ss.close();
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

客户端的哥们-->
package com.javami.kudyDemo;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class UploadServers implements Runnable
{

Socket socket ;
public UploadServers(Socket socket)
{
this.socket = socket;
}

@Override
public void run()
{
try
{
InputStream ips = socket.getInputStream();
OutputStream ops = socket.getOutputStream();
ops.write("连接成功,本站支持文件的上传".getBytes());

//接收文件名
byte[] buf = new byte[1024];
int len = ips.read(buf);
String fileName = new String(buf,0,len);
System.out.println("拿到文件名:"+fileName);

//创建文件
File file = new File("f:/a",fileName);
if(!file.createNewFile())
{
ops.write("该文件已经存在".getBytes());
return;
}
ops.write("可以上传文件".getBytes());

//接收文件的大小
len = ips.read(buf);
String str = new String(buf,0,len);
int fileSize = (int)Integer.parseInt(str);

//接收客户端的文件
saveFile(ips,file,fileSize);//接收的内容.我的文件名  --> 接收过来的长度
//接收从客户端发送过来的文件
ops.write("文件上传完毕,恭喜-->使用了".getBytes());
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}

}

private void saveFile(InputStream ips, File file, int fileSize) throws IOException
{
BufferedInputStream bis =
new BufferedInputStream(ips);//读取内容-->会发生阻塞..
BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream(file));
int ch;
System.out.println("文件上传中,请等下------");
for(int i=0; i<fileSize; i++)
{
ch = bis.read();
bos.write(ch);
}
bos.close();//不需要把底层的所关闭~~
}

}


----------以下内容为自己用文本工具编写..功能实现得比较简单点.以上一样..

客户端:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
class MyChlient
{
/*
客户端
:
文件的上传功能
*/
public static void main(String[] args)
{
Socket socket = null;
try
{
socket = new Socket("127.0.0.1",8888);
InputStream ips = socket.getInputStream();
OutputStream ops = socket.getOutputStream();
Thread.sleep(10);
byte [] buf = new byte[1024];
int len = ips.read(buf);
System.out.println(new String(buf,0,len));

//发送文件名
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
String line ;
System.out.println("请输入文件的路径:");
File file ;
while(true)
{
line = br.readLine();
file = new File(line);
if(file.isFile())
{
ops.write(file.getName().getBytes());//把文件的名字发过去
break;
}
if(!file.exists())
System.out.println("该目录不存在");
else
System.out.println("不给力~~~");
}

//接收客户端反馈信息
len = ips.read(buf);
String info = new String(buf,0,len);
if(!"已经成功创建文件".equals(info))
return;
System.out.println(info);

//上传文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(ops);
int ch;
while((ch=bis.read())!=-1)
{
bos.write(ch);
}
bos.flush();//底层的流我们要刷新一下
bis.close();//关闭一下流

}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
if(socket!=null)
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
服务端:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.ServerSocket;
class MyServer
{
public static void main(String[] args)
{
ServerSocket ss = null;
try
{
ss = new ServerSocket(8888);
System.out.println("服务器正在监听8888端口");
while(true)
{
Socket socket = ss.accept();
System.out.println(socket.getInetAddress().getHostAddress());//获取到连接上来的主机
new Thread(new ThreadServer(socket)).start();
}
}
catch (Exception e)
{
e.printStackTrace();
}finally
{
try
{
if(ss!=null)
ss.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}

服务端的多线程实现类
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
class ThreadServer implements Runnable
{
Socket socket;
public ThreadServer(Socket socket)
{
this.socket = socket;
}
public void run()
{
try
{
InputStream ips = socket.getInputStream();
OutputStream ops = socket.getOutputStream();
ops.write("欢迎光临本小站,本小站提供文件上传的服务:".getBytes());

//接收用户发送的文件名
File file;
byte[] buf = new byte[1024];
int len = ips.read(buf);
String fileName = new String(buf,0,len);
System.out.println("服务器已经获取到文件名:"+fileName);
file = new File("f:/upload",fileName);
if(!file.createNewFile())
{
ops.write("文件已经存在".getBytes());
return;
}
ops.write("已经成功创建文件".getBytes());

//接收用户的文件
byte [] b = new byte[ips.available()];
BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream(file));//我们把内容写到这边来
int ch;
while((ch=ips.read())!=-1)
{
bos.write(ch);
}
bos.close();
}
catch (Exception e)
{
e.printStackTrace();
}finally
{
try
{
if(socket!=null)
socket.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}


更为明确的字符反转功能:

客户端
:
package com.javami.kudyDemo.TCP;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class MySocket
{
public static void main(String[]args)
{
Socket socket  = null;
try
{
socket = new Socket("127.0.0.1",8888);
InputStream ips = socket.getInputStream();
OutputStream ops = socket.getOutputStream();
byte[] buf = new byte[1024];
int len = ips.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
String line ;
System.out.println("请输入你需要转换的数据");
while(true)
{
line = br.readLine();
if("quit".equals(line))
return;
ops.write((line).getBytes());
Thread.sleep(10);
System.out.println("数据反转中......");
len = ips.read(buf);
System.out.println(new String(buf,0,len));
}
}catch(Exception e)
{
e.printStackTrace();
}finally
{
if(socket!=null)
try
{
socket.close();
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

服务端:
package com.javami.kudyDemo.TCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServer
{
public static void main(String[]args)
{
ServerSocket ss = null;
try
{
ss = new ServerSocket(8888);

while(true)
{
Socket socket = ss.accept();//监听成功.服务器返回欢迎的信
new Thread(new ThreadSocket(socket)).start();
}
}catch(Exception e)
{
e.printStackTrace();
}finally
{

}
}
}
他哥们:
package com.javami.kudyDemo.TCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class ThreadSocket implements Runnable
{

Socket socket ;
public ThreadSocket(Socket socket)
{
this.socket = socket;
}
@Override
public void run()
{
try
{
InputStream ips = socket.getInputStream();
OutputStream ops = socket.getOutputStream();
ops.write("提供字母转换:".getBytes());
byte[] buf = new byte[1024];
int len;
while(true)
{
len = ips.read(buf);
String str = new String(buf,0,len);
if("quit".equals(str))
return;
StringBuilder sb = new StringBuilder(str);
sb = sb.reverse();//反转
ops.write(sb.toString().getBytes());
}
} catch (IOException e)
{
e.printStackTrace();
}finally
{
try
{
socket.close();
}catch(IOException e)
{
e.printStackTrace();
}
}

}

}


Dcp的复习:

package com.javami.kudyDemo.TCP;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class MyOne
{
public static void main(String[]args)
{
DatagramSocket dgs = null;
DatagramPacket dgp = null;

//封包
String line = "i live china";
byte[] buf = line.getBytes();
try
{
dgs = new DatagramSocket();
dgp =
new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),8888);
dgs.send(dgp);//发包
} catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}finally
{
if(dgs!=null)
dgs.close();
}

}
}

package com.javami.kudyDemo.TCP;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class MyTwo
{
public static void main(String[]args)
{
DatagramSocket ds = null;
try
{
ds = new DatagramSocket(8888);
DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
ds.receive(dp);
byte[] data = dp.getData();
System.out.println(new String(data,0,dp.getLength()));
}catch(Exception e)
{
e.printStackTrace();
}

}
}


:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: