前些天和我们的一个邮件服务商对接,双方需要进行一些通讯,对方是java团队,而作为.net团队的我们,只能公布出去的是一个wcf的basicbinding,想不

Socket实现

javaSocket通信原理

图片 1

第一步:服务端创建serverSocket,启动服务、监听端口

 

/**
 * 天气查询服务端
 * @author SMN
 * @version V1.0
 */
public class WeatherServer {

    public static void main(String[] args) throws IOException {
        //创建socket服务端对象
        ServerSocket serverSocket = new ServerSocket(1234);
        System.out.println("服务端已启动。。。。");
        while(true){
            //监听客户端连接,accept方法为阻塞方法
            Socket socket = serverSocket.accept();
            //获取输入流准备取客户端发送的数据
            DataInputStream dataInputStream =null;
            DataOutputStream dataOutputStream =null;
            try {
                //包括为datainputstream
                dataInputStream = new DataInputStream(socket.getInputStream());
                //读取数据
                String in_data = dataInputStream.readUTF();
                //打印读取的数据
                System.out.println("from client.."+in_data);
                //创建输出流准备输出数据
                dataOutputStream = new DataOutputStream(socket.getOutputStream());
                System.out.println("to client..."+"晴朗");
                dataOutputStream.writeUTF("晴朗");
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                //释放资源
                if(dataOutputStream!=null){
                    dataOutputStream.close();
                }
                if(dataInputStream!=null){
                    dataInputStream.close();
                }
            }
        }
    }
}

 

第二步:客户端创建socket,连接服务端

 

/**
 * 天气查询客户端
 * @author SMN
 * @version V1.0
 */
public class WeatherClient {

    public static void main(String[] args) throws UnknownHostException, IOException {
        while(true){
            //socket客户端对象
            Socket socket = null;
            //输出流用于发送数据
            DataOutputStream dataOutputStream = null;
            //输入流用于接收数据
            DataInputStream dataInputStream = null;
            try {
                //创建socket
                socket = new Socket("127.0.0.1", 1234);
                socket.setSoTimeout(10000);//超时时间为10秒,防止服务端处理超时返回数据失败
                //创建输出流准备向服务端发送数据
                dataOutputStream = new DataOutputStream(socket.getOutputStream());
                dataOutputStream.writeUTF("郑州");
                System.out.println("to server...."+"郑州");

                //接收服务端发送的数据
                dataInputStream = new DataInputStream(socket.getInputStream());
                String resultString = dataInputStream.readUTF();

                System.out.println("from server..."+resultString);
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                //释放资源
                if(socket!=null){
                    socket.close();
                }
                if(dataOutputStream!=null){
                    dataOutputStream.close();
                }
                if(dataInputStream!=null){
                    dataInputStream.close();
                }

            }
        }
    }
}

到问题来了,对方不知道怎么去调用这个basic,可能他们水平有点菜,有点尴尬,不得已我来研究研究,其实只要知道公布的wsdl,对什么语言都是很简单的。

第一个例子

第一步:服务端开发

1.编写SEI(Service Endpoint Interface),SEI在webservice中称为portType,在java中称为接口。

/**
 * 天气查询服务接口
 * @author SMN
 * @version V1.0
 */
public interface WeatherInterface {
    //天气查询
    public String queryWeather(String cityName);  
}

2.编写SEI实现类,此类作为webservice提供服务类

/**
 * 天气查询服务接口实现类
 * @author SMN
 * @version V1.0
 */
@WebService
public class WeatherInterfaceImpl implements WeatherInterface {

    @Override
    public String queryWeather(String cityName) {
        System.out.println("from client.."+cityName);
        String result = "晴朗";
        System.out.println("to client..."+result);
        return result;
    }

    public static void main(String[] args) {
        //发送webservice服务
        Endpoint.publish("http://192.168.1.100:1234/weather", new WeatherInterfaceImpl());
    }

}

注意:

SEI实现类中至少要有一个非静态的公开方法需要作为webservice服务方法。

public class 上边要加上@WebService 

3.endpoint发布服务,代码在实现类的主方法中

第二步:查看wsdl

Webservice发布成功,通过wsdl查看webservice发布的正确性

1.在地址栏输入(注意后面的参数?wsdl)

http://192.168.1.100:1234/weather?wsdl 

2.Wsdl不是webService,只是获取一个用于描述WebService的说明文件

3.wsdl- WebServiceDescriptionLanguage,是以XML文件形式来描述WebService的”说明书”,有了说明书,我们才可以知道如何使用或是调用这个服务.

第三步:Wsimport生成客户端调用类

Wsimport介绍

wsimport是jdk自带的webservice客户端工具,可以根据wsdl文档生成客户端调用代码(java代码).当然,无论服务器端的WebService是用什么语言写的,都可以生成调用webservice的客户端代码,服务端通过客户端代码调用webservice。

wsimport.exe位于JAVA_HOME\bin目录下.

常用参数为:

-d<目录>  – 将生成.class文件。默认参数。

-s<目录> – 将生成.java文件。

-p<生成的新包名> -将生成的类,放于指定的包下。

(wsdlurl) –

示例:

C:/> wsimport –s .

注意:-s不能分开,-s后面有个小点

 

 

客户端生成注意事项:

  1. 可以通过java –version检查你当前的版本号保存是jdk1.6以上。Jdk1.6.0_13以后的版本支持jaxws2.1。
  2. 在Eclipse中创建一个空的java工程为wsimport,此工程作为存放客户端代码。
  3. cmd命令行进入此wsimport
    工程的src目录,

输入以下命令:

  图片 2

参数说明:-s是指编译出源代码文件,后面的.(点)指將代码放到当前目录下.

最后面的http….是指获取wsdl说明书的地址.

  

如果wsdl文件在本地,可以这样使用:Wsimport –s .
file:///d:\WeatherWebService.wsdl

注意:这里可能会遇到类似这样的错误:

图片 3

我们可以把wsdl文件下载到本地,删除掉文件中所有的<s:element
ref=”s:schema”/>即可解决

    4.生成完成,刷新Eclipse中wsimport工程,将src下生成.java文件代码Copy到webservice客户端工程(见下)中。 

第四步:客户端编写

 

/**
 * 天气查询客户端
 * @author SMN
 * @version V1.0
 */
public class WeatherClient {
    public static void main(String[] args) {
        //创建服务视图
        WeatherInterfaceImplService weatherInterfaceImplService =new WeatherInterfaceImplService();
        //通过服务视图得到服务端点
        WeatherInterfaceImpl weatherInterfaceImpl= weatherInterfaceImplService.getPort(WeatherInterfaceImpl.class);
        //调用webservice服务方法
        String result = weatherInterfaceImpl.queryWeather("郑州");
        System.out.println(result);
    }
}

 

一:案例

Webservice工作原理:

图片 4

Socket  是基于TCP/ip的传输层协议

Webservice是基于http协议传输数据,http是基于tcp的应用层协议

Webservice采用了基于http的soap协议传输数据。

Socket接口通过流传输,不支持面向对象。

Webservice 接口支持面向对象,最终webservice将对象进行序列化后通过流传输。

 

结论:

Webservice采用soap协议进行通信,底层基于socket通信,webservice不需专门针对数据流的发送和接收进行处理,是一种跨平台的面向对象远程调用技术。

 

Socket和webservice:应用场景

Socket适用于传输大数量的数据,缺点:接口传输的数据需要手动解析,socket通信的接口协议需要自定义,比如:自定义一种字符串拼接的格式,比如自定义的xml数据,自定义麻烦之处在接口调用方和接口服务端需要互相讨论确定接口的协议内容,不方便,好处:适用于传输大数量的数据。

Webservcie,由于是遵循标准的soap协议,soap 协议的内容格式固定,soap协议传递的内容是xml数据,由于webservice是基于http的,所以简单理解为soap=http+xml,适用于没有性能要求情况下且数据传输量小,推荐在公开接口上使用webservice,因为soap协议的标准的。

 

     
为了方便,我也不特意写什么代码了,就用vs里面的wcf服务模板创建一下,详细内容如下:

什么是webservice?

  Web service 即web服务,它是一种跨编程语言和跨操作系统平台的远程调用技术即跨平台远程调用技术。

  采用标准SOAP(Simple Object Access Protocol)
 协议传输,soap属于w3c标准。Soap协议是基于http的应用层协议,soap协议传输是xml数据。 

  采用wsdl作为描述语言即webservice使用说明书,wsdl属w3c标准。

  xml是webservice的跨平台的基础,XML主要的优点在于它既与平台无关,又与厂商无关。

  XSD,W3C为webservice制定了一套传输数据类型,使用xml进行描述,即XSD(XML Schema
Datatypes),任何编程语言写的webservice接口在发送数据时都要转换成webservice标准的XSD发送。

 1     // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。
 2     // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 Service1.svc 或 Service1.svc.cs,然后开始调试。
 3     public class Service1 : IService1
 4     {
 5         public string GetData(int value)
 6         {
 7             return string.Format("You entered: {0}", value);
 8         }
 9 
10         public CompositeType GetDataUsingDataContract(CompositeType composite)
11         {
12             if (composite == null)
13             {
14                 throw new ArgumentNullException("composite");
15             }
16             if (composite.BoolValue)
17             {
18                 composite.StringValue += "Suffix";
19             }
20             return composite;
21         }
22     }

webService三要素

 

soap

SOAP即简单对象访问协议(Simple Object Access
Protocal) 是一种简单的基于
XML
的协议,它使应用程序通过
HTTP
来交换信息,简单理解为soap=http+xml。

Soap协议版本主要使用soap1.1、soap1.2

SOAP不是webservice的专有协议,其他应用协议也使用soap传输数据。例如,SMTP、tr069等。

       
然后F5运行一下,就可以看到这样的一个wcf测试客户端,有服务地址,有提供的两个方法契约。

wsdl

WSDL 是基于 XML 的用于描述Web Service及其函数、参数和返回值。通俗理解Wsdl是webservice的使用说明书。 

 

UDDI

UDDI 是一种目录服务,通过它,企业可注册并搜索
Web
services。企业将自己提供的Web Service注册在UDDI,也可以使用别的企业在UDDI注册的web service服务,从而达到资源共享。

UDDI旨在将全球的webservcie资源进行共享,促进全球经济合作。

但是使用webservice并不是必须使用UDDI,因为用户通过WSDL知道了web service的地址,可以直接通过WSDL调用webservice。

图片 5

 

 

WSDL

wsdl 说明书结构

<service>     整个webservice的服务视图,它包括了所有的服务端点

<binding>     为每个端口定义消息格式和协议细节

<portType>  描述 web service可被执行的操作,以及相关的消息,通过binding指向portType

<message>   定义一个操作(方法)的数据参数(可有多个参数)

<types>        定义 web service
使用的全部数据类型

wsdl 说明书阅读方式

从下往上读

先找到服务视图,通过binging找到protType,找到了protType就找到了我们要调用的webservice方法。

查看wsdl说明要从下往上看:

1服务视图(根)

图片 6

图片 7

2通过服务视图,bingding到porttype

图片 8

3、调用portType的方法

二:java调用

使用javax.xml.ws.Service进行客户端编程(常用方法)

 

  1. 使用web service client

步骤

 

第一步:创建URL,指定资源地址即wsdl地址

 

第二步:创建Qname,指定命名空间和视图名称

 

第三步:创建服务视图对象service

 

第四步:从服务视图中得到服务端点即服务接口(这里需要服务接口类型,可使用wsimport生成后只留下porttype)

 

第五步:通过服务端点调用服务方法

 

/**
 * 使用javax.xml.ws.Service调用webservice服务
 * @author SMN
 * @version V1.0
 */
public class WeatherClient2 {
    public static void main(String[] args) throws MalformedURLException {
        //定义url,参数为wsdl地址
        URL url = new URL("http://192.168.1.100:1234/weather?wsdl");
        //定义qname,第一个参数是命名空间,第二个参数名称是wsdl里边的服务名
        QName qName = new QName("http://impl.sei.jaxws.ws.itcast.cn/", "WeatherInterfaceImplService");
        //创建服务视图
        Service service = Service.create(url, qName);
        //通过服务视图得到服务端点
        WeatherInterfaceImpl weatherInterfaceImpl =service.getPort(WeatherInterfaceImpl.class);
        //调用webservice
        System.out.println(weatherInterfaceImpl.queryWeather("郑州"));
    }
}

 

     其实在eclipse的新建项目中有一个Web Service Client
模板,这个里面就可以将wsdl转换为proxy的java代码,有一点像C#中的服务引用,是不是,

使用Service调用和Wsimport代码调用方式区别:

Wsimport生成代码调用webservice无法指定webservice的地址,使用生成的服务视图类获取服务端点(postType)实例。

Service调用Webservice可以指定webservice的地址,只需要服务端点的接口即可获取服务端点实例。

 

下面就一步一步操作下:

《1》 新建一个java project,或者dynamic
web project都是可以的,本次测试只新建一个MyJavaTest 的project。

图片 9

 

《2》 然后使用 WebService Client的模板
File  => Other =>Web Services => Web Service Client
即可。

图片 10

 

《3》在Service definition
选项中输入我们的wcf服务地址:

         在svc后面加上一个wsdl,这样就方便java
proxy找到哈,然后左下角有一个“温度计”,调到start client 模式就

       
好,然后继续点击下一步,详细如下图:

图片 11

 

《4》
下图就表示生成好的代码将放入到哪一个目录下,这个没什么好说的。

图片 12

 

《5》然后点击finish,现在你会发现,你多了几个自动化的java类,便捷性和visual
studio有的一拼。

图片 13

 

好了,自动化的类都出来了,接下来我只需要新建了一个入口的Program类,是不是就可以敲定了。。。

 1 package com.datamip;
 2 
 3 import java.rmi.RemoteException;
 4 
 5 import org.tempuri.IService1Proxy;
 6 
 7 public class Program {
 8 
 9     public static void main(String[] args) throws RemoteException {
10 
11         IService1Proxy proxy = new IService1Proxy();
12 
13         String result = proxy.getData(12345);
14 
15         System.out.println(result);
16     }
17 
18 }

图片 14

不过要吐槽的是,IService1Proxy居然是一个类,我还以为是接口呢,思维定势吧~~~

 

  1. 使用wsimport小工具

       
其实java的jdk里面有很多的实用小工具,其中就有一款wsimport.exe,它就可以用来根据wsdl生成自动化的proxy类,和.net的svcutil的功能

是一样的。

图片 15

 

 
由于jdk路径都配置到了环境变量中,就可以在cmd中看一下wsimport需要的参数。

C:\Users\hxc>wsimport
缺少 WSDL_URI


用法: wsimport [options] <WSDL_URI>

\其中 [options] 包括:
  -b <path>                 指定 jaxws/jaxb 绑定文件或附加模式
                            (每个 <path> 都必须具有自己的 -b)
  -B<jaxbOption>            将此选项传递给 JAXB 模式编译器
  -catalog <file>           指定用于解析外部实体引用的目录文件
                            支持 TR9401, XCatalog 和 OASIS XML 目录格式。
  -d <directory>            指定放置生成的输出文件的位置
  -encoding <encoding>      指定源文件所使用的字符编码
  -extension                允许供应商扩展 - 不按规范
                            指定功能。使用扩展可能会
                            导致应用程序不可移植或
                            无法与其他实现进行互操作
  -help                     显示帮助
  -httpproxy:<host>:<port>  指定 HTTP 代理服务器 (端口默认为 8080)
  -keep                     保留生成的文件
  -p <pkg>                  指定目标程序包
  -quiet                    隐藏 wsimport 输出
  -s <directory>            指定放置生成的源文件的位置
  -target <version>         按给定的 JAXWS 规范版本生成代码
                            默认为 2.2, 接受的值为 2.0, 2.1 和 2.2
                            例如, 2.0 将为 JAXWS 2.0 规范生成兼容的代码
  -verbose                  有关编译器在执行什么操作的输出消息
  -version                  输出版本信息
  -wsdllocation <location>  @WebServiceClient.wsdlLocation 值
  -clientjar <jarfile>      创建生成的 Artifact 的 jar 文件以及
                            调用 Web 服务所需的 WSDL 元数据。
  -generateJWS              生成存根 JWS 实现文件
  -implDestDir <directory>  指定生成 JWS 实现文件的位置
  -implServiceName <name>   生成的 JWS 实现的服务名的本地部分
  -implPortName <name>      生成的 JWS 实现的端口名的本地部分

\扩展:
  -XadditionalHeaders              映射标头不绑定到请求或响应消息不绑定到
                                   Java 方法参数
  -Xauthfile                       用于传送以下格式的授权信息的文件:
                                   http://username:password@example.org/stock?wsdl
  -Xdebug                          输出调试信息
  -Xno-addressing-databinding      允许 W3C EndpointReferenceType 到 Java 的绑定
  -Xnocompile                      不编译生成的 Java 文件
  -XdisableAuthenticator           禁用由 JAX-WS RI 使用的验证程序,
                                   将忽略 -Xauthfile 选项 (如果设置)
  -XdisableSSLHostnameVerification 在提取 wsdl 时禁用 SSL 主机名
                                   验证

\示例:
  wsimport stock.wsdl -b stock.xml -b stock.xjb
  wsimport -d generated http://example.org/stock?wsdl


C:\Users\hxc>

这其中,大概知道下面4个参数就好说了。

《1》 url: 你需要生成代理类的数据源,也就是wsdl文件

《2》 -d:  生成的proxy文件需要存放的路径

《3》-p:   生成proxy类的包名。

《4》-keep:保存生成的文件名

接下来我们就cmd试一下:

C:\Users\hxc>wsimport http://localhost:54248/Service1.svc?wsdl -d c:\\2\\ -p com.datamip.proxy -keep
正在解析 WSDL...



正在生成代码...


正在编译代码...


C:\Users\hxc>

 

好了,接下来就可以将“文件夹2”中的proxy类copy到project中,如下图:

图片 16

 

看起来是不是很完美,那接下来要做的事情就是coding验证啦~~~

图片 17

 

最后还有一种笨的方法,那就是通过fiddler抓取webservice通讯的参数,然后通过httppost模拟提交,也是可以的。。。好了,本篇就和大家说到

这里,希望对你有帮助。

 

相关文章