java 网络编程之TCP通信和简单的文件上传功能实例
TCP通信需要明确的几点:
tcp通信是面向连接的,需要先启动服务端,再启动客户端。
客户端和服务端都要创建套接字对象,客户端需要指定服务端套接字(ip+port),而服务端必须指定服务端口。
Socketclient_socket=newSocket("192.168.100.17",8888);//客户端套接字(Socket类的套接字为已连接套接字)
ServerSocketlisten_socket=newServerSocket(8888);//服务端套接字,此时为监听套接字(已经bind()地址和端口了)
服务端需要使用accept()方法将监听套接字转变为已连接套接字。这个监听套接字可以生成多个已连接套接字,这样连接后还能监听其他客户端的请求。因此,这里应该使用多线程实现并发访问。获得了已连接套接字,就可以获取很多客户端的信息,例如客户端的ip地址,发送请求的端口等。
Socketserver_scoket=socket.accept(); Socketserver_scoket2=socket.accept(); Socketserver_scoket3=socket.accept();
服务端要实现并发连接,大致使用如下代码:其中ThreadTask是线程任务对象。
publicstaticvoidmain(String[]args)throwsIOException{
ServerSocketlisten_sock=newServerSocket(8888);//监听套接字只需创建一个,因此在任务之外
while(true){//每建立一个连接,就开启一个线程
Socketconn_sock=listen_sock.accept();//没有新连接进来时,main主线程阻塞在此
newThread(newThreadTask(conn_sock)).start();
}
}
客户端需要根据已连接套接字获取输出流,服务端需要根据套接字获取输入流。当然,既然有了已连接套接字,那么获取无论哪一端都可以获取到输入流、输出流。
OutputStreamsend_stream=client_socket.getOutputStream();//客户端获取输出流 InputStreamrecv_stream=server_socket.getInputStream();
服务端应主动关闭已连接套接字,至于监听套接字则在合适的地方关闭。
服务端应该循环不断地负责接收。
简单的Client端:
importjava.io.IOException;
importjava.io.OutputStream;
importjava.net.Socket;
publicclassTCPClient{
publicstaticvoidmain(String[]args){
//1.创建客户端套接字
Socketc_sock=null;
OutputStreamclient_outstream=null;
try{
c_sock=newSocket("192.168.0.124",8888);
//2.获取输出流
client_outstream=c_sock.getOutputStream();
//3.输出数据
client_outstream.write("Hello,i'mcoming".getBytes());
}catch(IOExceptione){
e.printStackTrace();
}finally{
if(c_sock!=null){
try{
c_sock.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
}
}
简单的Server端:
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.net.ServerSocket;
importjava.net.Socket;
publicclassTCPServer{
publicstaticvoidmain(String[]args){
//1.创建监听套接字
ServerSocketlisten_sock=null;
try{
listen_sock=newServerSocket(8888);
}catch(IOExceptioni){
i.printStackTrace();
}
Socketserver_sock=null;
InputStreamin_sock=null;
while(true){
try{
//2.和客户端建立连接,生成已连接套接字,并获取客户端ip地址
server_sock=listen_sock.accept();
Stringclient_ip=server_sock.getInetAddress().getHostAddress();
System.out.println("Client:"+client_ip+"connected");
//3.根据已连接套接字,获取输入流,读取客户端发送的数据
in_sock=server_sock.getInputStream();
BufferedReaderbufr=newBufferedReader(newInputStreamReader(in_sock));
Stringline=null;
while((line=bufr.readLine())!=null){
System.out.println(line);
}
//4.关闭已连接套接字
server_sock.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
}
以下是tcp实现文件上传功能:
客户端除了套接字的输出流,还有读取本地文件的输入流,还有套接字的输入流来读取来自服务端的反馈信息。
服务端也同样有三流:套接字的输入、输出流,写入上传目标文件的输出流。
客户端读取本地文件的所有数据后,需要使用套接字的shutdownOutput()来通知服务端套接字的输出流已到末尾。
服务端为了能为多人提供上传功能,需要使用多线程实现并发连接。
Client端:
importjava.io.BufferedReader;
importjava.io.FileInputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.OutputStream;
importjava.net.Socket;
publicclassUploadClient{
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
Stringserver_addr="192.168.0.124";
intserver_port=8888;
Socketsend_sock=null;
FileInputStreamlocal_read=null;
try{
//1.客户端套接字
send_sock=newSocket(server_addr,server_port);
//2.获取连接管道的输出流
OutputStreamsend_stream=send_sock.getOutputStream();
//3.字节输入流读取本地文件数据,并使用套接字的输出流发送出去
local_read=newFileInputStream("d:/myjava/net/SQL.docx");
byte[]buf=newbyte[1024];
intlen=0;
while((len=local_read.read(buf))!=-1){
send_stream.write(buf,0,len);
}
//4.标记输出流到结尾
send_sock.shutdownOutput();
//5.接收服务端的反馈数据,如上传成功,上传失败等
InputStreamrecv_stream=send_sock.getInputStream();
BufferedReaderack_recv=newBufferedReader(newInputStreamReader(recv_stream));
Stringline=null;
while((line=ack_recv.readLine())!=null){
System.out.println(line);
}
}catch(IOExceptioni){
i.printStackTrace();
}finally{
if(send_sock!=null){
try{
send_sock.close();
local_read.close();
}catch(IOExceptioni1){
i1.printStackTrace();
}
}
if(local_read!=null){
try{
local_read.close();
}catch(IOExceptioni2){
i2.printStackTrace();
}
}
}
}
}
Server端:
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.OutputStream;
importjava.net.ServerSocket;
importjava.net.Socket;
publicclassUploadServer{
publicstaticvoidmain(String[]args)throwsIOException{
ServerSocketlisten_sock=newServerSocket(8888);//监听套接字只需创建一个,因此在任务之外
while(true){//每建立一个连接,就开启一个线程
Socketconn_sock=listen_sock.accept();//没有新连接进来时,main主线程阻塞在此
newThread(newUploader(conn_sock)).start();
}
}
}
classUploaderimplementsRunnable{
privateFiledest_dir=newFile("d:/temp");//上传目录
privateSocketconn_sock=null;//连接套接字
InputStreamrecv_stream=null;
FileOutputStreamdest_stream=null;
Uploader(Socketconn_sock)throwsIOException{
this.conn_sock=conn_sock;
}
publicvoidrun(){
try{
if(!dest_dir.exists()){
dest_dir.mkdirs();
}
//1.获取连接管道的输入流
recv_stream=conn_sock.getInputStream();
//客户端ip
Stringclient_ip=conn_sock.getInetAddress().getHostAddress();
System.out.println(client_ip+".....connected");
//2.文件的上传位置,即输出目标,以ip命名。如果文件已存在,则使用括号加数字新建文件,如"192.168.100.23(1).txt"
Filedest_file=newFile(dest_dir,client_ip+".docx");
intcount=1;
while(dest_file.exists()){
dest_file=newFile(dest_dir,client_ip+"("+count+")"+".docx");
count++;
}
//3.读取数据并写入目标文件
dest_stream=newFileOutputStream(dest_file);
byte[]buf=newbyte[1024];
intlen=0;
while((len=recv_stream.read(buf))!=-1){
dest_stream.write(buf,0,len);
}
//4.向客户端反馈信息
OutputStreamack_send=conn_sock.getOutputStream();
byte[]text="uploadsuccessful!".getBytes();
ack_send.write(text);
}catch(IOExceptione1){
e1.printStackTrace();
}finally{
if(dest_stream!=null){
try{
dest_stream.close();
}catch(IOExceptioni){
i.printStackTrace();
}
}
if(conn_sock!=null){
try{
conn_sock.close();
}catch(IOExceptioni){
i.printStackTrace();
}
}
}
}
}
以上这篇java网络编程之TCP通信和简单的文件上传功能实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。
