【java基础】——网络编程

时间:2023-02-24 22:39:13

一、网络编程概述

1、计算机网络

计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的的管理和协调下,实现资源共享和信息传递的计算机系统。

2、什么是网络编程

网络编程就是用来实现网络互联的不同计算机上运行的程序间可以进行数据交换。

3、网络模型

①网络模型一般是指OSI参考模型、TCP/IP参考模型:
  • OSI参考模型分七层:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
  • TCP/IP参考模型分四层:应用层、传输层、网际层、主机至网络层。
②网络模型图如下图所示:
【java基础】——网络编程
③网络模型的七层概述:
  • 物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由10转化为电流强弱来进行传输,到达目的地后在转化为10,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。
  • 数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。

  • 网络层:主要将从下层接收到的数据进行IP地址(例192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。
  • 传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。

  • 会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)
  • 表示层:主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够能识别的东西(如图片、声音等)。
  • 应用层: 主要是一些终端的应用,比如说FTP(各种文件下载),WEBIE浏览),QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西.就是终端应用)。

4、网络通信三要素

①IP地址:InetAddress 网络中设备的标识,不易记忆,可用主机名。
在java中,为了方便我们的获取和操作,提供了一个InetAddress供我们使用。
InetAddress类的使用
在InetAddress类中,是没有构造方法的,
可通过getLocalHost()方法获取InetAddress对象,此方法是静态的,返回本类对象。
InetAddress i = InetAddress.getLocalHost();
常用功能:
  • getByName:获取任意主机

  • getHostName:主机名

  • getHostAddress:主机Ip地址

InetAddress常用方法演示如下:
package com.huang.socket.p1;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
*@author huangxiang
*@date 创建时间:2015年6月5日下午4:38:07
*@version 1.0
*/
public class IPDemo {

public static void main(String[] args) throws UnknownHostException {
//InetAddress ia = InetAddress.getByName("hx-pc");
//System.out.println(ia.getHostAddress());
//System.out.println(ia.getHostName());
//System.out.println(ia);//hx-pc/115.150.230.25
//InetAddress [] ia2 =InetAddress.getAllByName("hx-pc");

InetAddress ia = InetAddress.getLocalHost();
System.out.println(ia.toString());//hx-pc/100.74.18.52
System.out.println(ia.getHostAddress());//100.74.18.52
System.out.println(ia.getHostName());//hx-pc

//也可以用数组的形式获取其ip
byte[] i = ia.getAddress();
for (int j = 0; j < i.length; j++) {
if(!(j == i.length-1))
System.out.print(i[j]+".");
else {
System.out.println(i[j]);//100.74.18.52
}
}
/*常用方法
* byte[] getAddress()
返回此 InetAddress 对象的原始 IP 地址。
static InetAddress[] getAllByName(String host)
在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组。
static InetAddress getByAddress(byte[] addr)
在给定原始 IP 地址的情况下,返回 InetAddress 对象。
static InetAddress getByAddress(String host, byte[] addr)
根据提供的主机名和 IP 地址创建 InetAddress。
static InetAddress getByName(String host)
在给定主机名的情况下确定主机的 IP 地址。
String getCanonicalHostName()
获取此 IP 地址的完全限定域名。
String getHostAddress()
返回 IP 地址字符串(以文本表现形式)。
String getHostName()
获取此 IP 地址的主机名。
static InetAddress getLocalHost()
返回本地主机。

*/
}
}
②端口号
a、物理端口,端口号指的是网卡口。
b、逻辑端口,我们指的就是逻辑端口。
  • A:每个网络程序都会至少有一个逻辑端口。

  • B:用于标识进程的逻辑地址,不同进程的标识。
  • C:有效端口:0~65535,其中0~1024系统使用或保留端口。

③传输协议:UDP和TCP
传输协议主要有两种,一种是UDP,一种是TCP
a、UDP:
是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址。它在网络上以任何可能的路径传往目的地,因此能否到达目的地、到达目的地的时间、内容的准确性都是不能被保证的
b、TCP:
是一种面向连接的保证可靠传输的协议。通过TCP,得到的是一个顺序的无差错的数据流,发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常为sever socket)等待建立连接时,另一个socket可以要求进行连接,一旦两个连接建立,他们就可以进行双向的数据传输,双方都可以进行发送或者接收操作。

c、UDP和TCP的比较
UDP:1、每个数据报都给出了完整的地址信息,因此无需建立发送方和接收方的连接。           2、UDP传输数据限制大小,每个数据包的大小在64KB之内。           3、因其无连接,是个不可靠的协议。发送方所发送的数据不一定以相同的次序到达接收方。           4、不需要建立连接,传输速度快。
TCP :1、面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中需要连接时间。          2、在连接中进行大量数据传输,但传输数据大小有限制,一旦双方的数据连接建立起来,双方的socket就可以按照统一的格式进行大数据传输。          3、通过三次握手完成连接,是可靠协议。          4、必须建立连接,效率相对较低。

d、TCP和UDP的应用
  • TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽,因此TCP传输的效率不如UDP高。
  • UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。

二、基于Socket的java网络编程

1、什么是Socket?

          网络上的两个程序通过一个双向的通讯实现数据交换,这个双向链路的一端称为一个scoket。socket通常用来实现客户端和服务端的连接,socket是TCP/IP协议的一个十分流行的编程界面,一个socket由一个IP地址和一个端口号唯一确定。          但是,Socket所支持的协议并非TCP/IP一种,所以两者之间并没有什么必然的联系。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。

2、Socket通信的过程

Sever端Listen某个端口是否有连接请求,Client端向Sever端发出Connect请求,Server端向Client端回Accept消息,一个连接就建立起来了。Server端和Client端都可以通过send、write等方法与对方通信。
对于一个功能齐全的Socket,都要包含以下结构:
a、创建Socketb、打开连接到Socket的IO流c、按照一定的协议对Socket进行读写操作d、关闭socket
java在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。

3、UDP传输

①建立UDP传输的步骤:
  • 建立发送端和接收端(发送端和接收端是两个独立的运行程序)
  • 建立数据包
  • 调用Socket的发送和接收方法。
  • 关闭Socket。
②方法:
DatagramSocket类表示用来发送和接收数据包的套接字,在DatagramSocket上总是启用UDP广播发送,为了接收端能够接收到广播包应该将DatagramSocket绑定到通配符地址上。
接收:void receive(DatagramPacket dp);
发送:void send(DatagramPacket dp);
DatagramPacket类表示数据包。用来实现无连接包投递服务。每条报文仅根据该包中包含的信息,从一台机器路由到另一台机器
③步骤:
a、发送端的建立:
  • 建立UDPSocket服务,在此无需指定端口,也可以将端口加入。如果不指定的话,系统会随机分配一个端口,如第一次运行时端口为1093,那么第二次就会顺延为1094,再运行会一直顺延,因为之前的端口还没有得到释放,所以会顺延端口号值。
  • 提供数据,并将数据封装到数据包中
  • 通过socket服务的发送功能,将数据包发送出去
  • 关闭资源
代码实现如下:
package com.huang.socket.p1;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
*@author huangxiang
*@date 创建时间:2015年5月5日下午4:00:30
*@version 1.0
*/
/*
* 需求:通过udp传输方式,将一段文字数据发送出去。,
*定义一个udp发送端。
*思路:
*1,建立updsocket服务。
*2,提供数据,并将数据封装到数据包中。
*3,通过socket服务的发送功能,将数据包发出去。
*4,关闭资源。
*/
public class UdpSend {

public static void main(String[] args) throws Exception {
//创建udp服务,通过DatagramSocket对象
DatagramSocket ds = new DatagramSocket(2525);
//确定数据,并封装成数据包DatagramPacket(byte[] buf, int length, InetAddress address, int port)
byte[] buf = "黄祥的udp".getBytes();
DatagramPacket dp =
new DatagramPacket(buf,buf.length,InetAddress.getByName("hx-pc"),10000);
//通过socket服务,将数据包发送出去
ds.send(dp);
//关闭资源
ds.close();
}
//面向无连接,数据包丢失。
}

b、接收端的建立:
  • 定义UDPSocket服务。通常会监听一个端口,其实就是给这个接收网路应用程序定义数字标识,方便于明确哪些数据过来该应用程序可以处理。
  • 定义一个数据包,用来存储接收到的字节数据,因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
  • 通过socket服务的receive方法接收到的数据存入已定义好的数据包中。
  • 通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上。
  • 关闭资源
代码实现如下:
package com.huang.socket.p1;

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

/**
*@author huangxiang
*@date 创建时间:2015年5月5日下午6:13:27
*@version 1.0
*/
/*
* 需求:
定义一个应用程序,用于接收udp协议传输的数据并处理的。

定义udp的接收端。
思路:
1,定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。
方便于明确哪些数据过来该应用程序可以处理。
2,定义一个数据包,因为要存储接收到的字节数据。
因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3,通过socket服务的receive方法将收到的数据存入已定义好的数据包中。
4,通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。
5,关闭资源。
*/
public class UdpRece {

public static void main(String[] args) throws Exception {
//创建udpsocket服务,监听端口
DatagramSocket ds = new DatagramSocket(10000);
//定义一个数据包,存储接收到的数据
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
//通过socket的receive方法将数据存储到数据包中
ds.receive(dp);//receive是一个阻塞式方法,当没接收到数据时会一直等待。
//通过数据包的方法获取数据
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(ip+"::"+data+"::"+port);
//关闭资源
ds.close();
}
}
UDP小练习:通过键盘录入的方式来发送数据
package com.huang.socket.p1;
/*
* 用键盘录入的方式来发送数据
*/
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
*@author huangxiang
*@date 创建时间:2015年5月5日下午6:32:49
*@version 1.0
*/
//udp发送端。
public class UdpSend2 {

public static void main(String[] args) throws Exception {
//创建udp Socket服务
DatagramSocket ds = new DatagramSocket();
//键盘录入
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));

//读取数据
String line = null;

while((line=br.readLine())!= null){
if("886".equals(line))
break;
byte[] buf = new byte[1024];

DatagramPacket dp =
new DatagramPacket(buf, buf.length,InetAddress.getByName("hx-pc"),5520);
//发送数据。
ds.send(dp);
}
//关闭资源
ds.close();
}

}
package com.huang.socket.p1;import java.net.DatagramPacket;import java.net.DatagramSocket;/** *@author huangxiang *@date 创建时间:2015年5月5日下午6:33:03 *@version 1.0 *///udp接收端。public class UdpRece2 {public static void main(String[] args) throws Exception {@SuppressWarnings("resource")//创建socket服务DatagramSocket ds = new DatagramSocket(5520);//一直处于接收状态while(true){//定义接收数据的数据包byte[] buf = new byte[1024];DatagramPacket dp = new DatagramPacket(buf,buf.length);//接收数据ds.receive(dp);String ip = dp.getAddress().getHostAddress();String data = new String(dp.getData(),0,dp.getLength());System.out.println(ip+"::"+data);}}}

UDP练习2:一个聊天小程序。代码实现如下

package com.huang.socket.chat;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
*@author huangxiang
*@date 创建时间:2015年5月5日下午8:35:33
*@version 1.0
*/
//发送线程。
public class Send implements Runnable{
//定义socket服务引用。
public DatagramSocket ds;
public Send(DatagramSocket ds){
this.ds = ds;
}
@Override
public void run() {
try {
//键盘录入数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;

while((line = br.readLine())!=null){
byte[] buf = line.getBytes();

DatagramPacket dp =
new DatagramPacket(buf,buf.length,InetAddress.getByName("hx-pc"),10006);
//发送
ds.send(dp);

if("886".equals(line))
break;
}
//关闭资源。
ds.close();
} catch (Exception e) {
throw new RuntimeException("发送失败!");
}
}
}
package com.huang.socket.chat;import java.net.DatagramPacket;import java.net.DatagramSocket;/** *@author huangxiang *@date 创建时间:2015年5月5日下午8:35:43 *@version 1.0 *///接收线程public class Rece implements Runnable{//定义socket引用。public DatagramSocket ds;public Rece(DatagramSocket ds){this.ds = ds;}//复写run方法@Overridepublic void run() {try {while(true){//定义数据包byte[] buf = new byte[1024];DatagramPacket dp = new DatagramPacket(buf,buf.length);//接收数据包ds.receive(dp);//获取数据。String ip = dp.getAddress().getHostAddress();String data = new String(dp.getData(),0,dp.getLength());if("886".equals(data)){System.out.println(ip+".......离开聊天室");break;}System.out.println(ip+":"+data);} }catch (Exception e) {throw new RuntimeException("接收失败");}}}
package com.huang.socket.chat;import java.net.DatagramSocket;/** *@author huangxiang *@date 创建时间:2015年5月5日下午8:38:09 *@version 1.0 *//* * 需求:编写一个聊天程序 * 有收数据和发数据的部分。 * 这两部分需要同时执行。 * 这就需要用到多线程技术,一个线程控制收,一个线程控制发。 * 因为收和发的动作是不一致的,所以需要定义两个run()方法。将两个方法封装到不同的类中。 */public class ChatDemo{public static void main(String[] args) throws Exception{DatagramSocket sendSocket = new DatagramSocket();DatagramSocket receSocket = new DatagramSocket(10006);new Thread(new Send(sendSocket)).start();new Thread(new Rece(receSocket)).start();}}


4、TCP传输

①TCP分客户端和服务端,客户端对应的对象是Socket,服务端对应的对象是ServerSocket。

客户端在Socket对象建立时就可以去连接指定主机,因为TCP是面向连接的,所以在建立Socket服务时就要有服务端存在并连接成功,形成通路后在该通道进行数据传输。

②实现步骤:

客户端:
a.创建Socket服务并指定要连接的主机和端口。
b.获取Socket流中的输出流(输入流)。
c.通过输出流将数据发送到服务端(或通过输入流读取服务端发送过来的数据)。
d.关闭客户端。
服务端:
a.建立服务端的Socket服务,通过new ServerSocket()并监听一个端口。
b.获取连接过来的客户端对象。通过ServerSocket对象的accept方法,该方法是阻塞式方法。
c.客户端如果发送过来数据,那么服务端要使用对应的客户端对象并获取到该客户端对象的读取流来读取发过来的数据并打印在控制台。
d.关闭服务端。(可选操作)

下面通过一段代码来演示TCP传输

a、客户端。

package com.huang.socket.p2;

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

/**
*@author huangxiang
*@date 创建时间:2015年5月5日下午7:21:16
*@version 1.0
*/
/*
* 演示tcp传输。
1、tcp分客户端和服务端。
2、客户端对应的对象是Socket。
服务端对应的对象是ServerSocket。
*/
/*
* 客户端,
通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。
因为tcp是面向连接的。所以在建立socket服务时,
就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。
需求:给服务端发送给一个文本数据。
步骤:
1,创建Socket服务。并指定要连接的主机和端口。
*/
public class TcpClient {

public static void main(String[] args) throws UnknownHostException, IOException {
//创建socket服务,并指定要连接的主机和端口
Socket s = new Socket("hx-pc", 10000);

//为了获取数据,应获取socket中的输出流
OutputStream out = s.getOutputStream();

out.write("哈哈哈,老子来了".getBytes());

s.close();
}

}
b、服务端

package com.huang.socket.p2;

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

/**
*@author huangxiang
*@date 创建时间:2015年5月5日下午7:21:32
*@version 1.0
*/
/*
* 需求:定义端点接收数据并打印在控制台上。
服务端:
1,建立服务端的socket服务。ServerSocket();
并监听一个端口。
2,获取连接过来的客户端对象。
通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。
3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。
并打印在控制台。
4,关闭服务端。(可选)
*/
public class TcpSever {

public static void main(String[] args) throws Exception {
//建立socket服务。
ServerSocket ss = new ServerSocket(10000);

//获取连接过来的客户端对象
while(true){
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+".......connected");
//获取客户端发来的数据,使用客户端对象的读取流来读取。
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
ss.close();
}
}

}
③TCP小练习一:建立一个文本转换服务器。

a、客户端的代码实现

package com.huang.socket.p2;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
*@author huangxiang
*@date 创建时间:2015年5月5日下午7:59:48
*@version 1.0
*/
/*
* 需求:建立一个文本转换服务器。
* 客户端给服务端发送文本,服务端将文本转成大写返回给客户端。
* 而且客户端可以不停的进行文本转换,当客户端输入over时,转换结束
*
* 分析:
* 客户端--既然是操作设备上的数据,那么就可以使用io技术,并且按照io的规律来思考
* 源:键盘录入
* 目的:网络设备,网络输出流
* 因为操作的是文本数据,所以可以选择字符流
* 步骤:
* 1、建立服务
* 2、获取键盘录入
* 3、将数据发送给服务端
* 4、获取服务端返回的大写数据
* 5、关闭资源
* 都是文本数据,可以使用字符流进行操作,同时为了提高效率,加入缓冲区
*/
public class TransClient {

public static void main(String[] args) throws Exception{
// 1、建立服务
Socket s = new Socket("hx-pc",5555);
// 2、获取键盘录入
BufferedReader bf =
new BufferedReader(new InputStreamReader(System.in));
// 3、将数据发送给服务端
/*BufferedWriter bw =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));*/
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
// 4、获取服务端返回的大写数据
BufferedReader bufin =
new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bf.readLine())!=null){
if("over".equals(line))
break;
pw.println(line);
/*bw.write(line);
bw.newLine();
bw.flush();*/

String str = bufin.readLine();
System.out.println("sever:"+str);
}
// 5、关闭资源
//bw.close();
bf.close();
s.close();
}

}
b、服务端的代码实现:

package com.huang.socket.p2;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
*@author huangxiang
*@date 创建时间:2015年5月5日下午8:00:05
*@version 1.0
*/
/*
* 服务端:
* 源:socket读取流
* 目的地:socket输出流
* 都是文本,装饰
*/
public class TransServer {

public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(5555);

Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"........connected");
//读取socket中的输入流
BufferedReader br =
new BufferedReader(new InputStreamReader(s.getInputStream()));
//目的,socket输出流,将大写数据写入socket输出流,并发送给客户端
/*方法①:BufferedWriter bw =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));*/
//方法②:用printwriter
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
String line = null;
while((line=br.readLine())!=null){
System.out.println(line);
pw.println(line.toUpperCase());

/*bw.write(line.toUpperCase());
bw.newLine();
bw.flush();*/
}
s.close();
ss.close();
}

}
④TCP小练习2:上传图片

a、客户端实现

package com.huang.socket.uploadpic;

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

/**
*@author huangxiang
*@date 创建时间:2015年6月5日下午9:21:04
*@version 1.0
*/
/*
* 需求:上传图片
* 客户端:
* 1、服务端
* 2、读取客户端已有的图片数据
* 3、通过socket输出流将数据发给服务端
* 4、读取服务器反馈的信息
* 5、关闭资源
*/
public class PicClient {

public static void main(String[] args) throws Exception{
Socket s = new Socket("hx-pc",8888);

FileInputStream fis = new FileInputStream("测试.bmp");

OutputStream os = s.getOutputStream();

byte[] buf = new byte[1024];

int len = 0;
while((len=fis.read(buf))!=-1){
os.write(buf,0,len);
}

//告诉服务端已经写完。否则程序将出现异常
s.shutdownOutput();

InputStream is = s.getInputStream();
byte[] bufIn = new byte[1024];

int num = is.read(bufIn);
System.out.println(new String(bufIn,0,num));

fis.close();
s.close();
}

}
b、服务端实现

package com.huang.socket.uploadpic;

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

/**
*@author huangxiang
*@date 创建时间:2015年6月5日下午9:21:17
*@version 1.0
*/
public class PicServer {

public static void main(String[] args) throws Exception{
//创建服务端
ServerSocket ss = new ServerSocket(8888);
//获取客户端的数据
Socket s = ss.accept();
//通过socket输入流
InputStream is = s.getInputStream();
FileOutputStream fos = new FileOutputStream("D:\\copy.bmp");

byte[] buf = new byte[1024];

int len = 0;
while((len=is.read(buf))!=-1){
fos.write(buf,0,len);
}

//通过socket输出流

OutputStream os = s.getOutputStream();
os.write("上传成功".getBytes());
fos.close();
s.close();
ss.close();
}

}