0 0

java与C的socket通信,rst问题。0

情况是这样的,我作为C的客户端,与对方的java服务端通信。用socket收发xml报文。

流程是我这边发送一笔报文,对方经过业务处理之后,返回给我一笔报文,以xml形式发送(其实我觉得这个xml不重要,到最后都是转为字节流的形式发送)。

现在遇到的问题是这样的,我发送给对方的报文对方可以全部接收到,但是对方返回给我的报文我只能接收到一部分。

经过抓包发现,在对方发送给我一部分之后,对方发送了一个rst包过来,导致通信中断。

对方用telnet在win环境下模拟客户端发送报文,他可以全部接收返回的报文,所以怀疑是我这边C的客户端问题。

然后我这边用telnet测试,我这边在AIX环境下用telnet发送报文,与C客户端一样的,于是怀疑是网络问题。

但是对方用telnet在linux环境下模拟客户端发送报文,他也只能接收到一部分,因此,网络问题排除。

后来我这边用java写的客户端发送报文,又可以接收到全部的报文,所以,怀疑java下的socket通信与C之间存在差异,这个差异在java与telnet之间也存在。但是为什么在win下面的telnet可以成功接收?难道win的telnet和基于UNIX的telnet有什么区别?

求熟悉的人解答。

下面粘贴部分关键代码。

对方给的部分java服务端代码:

private void sendBackData(InputStream outputXML) {
		mLogger.info("Socket服务端准备向客户端返回数据。");
		OutputStream outputStream = null;

		try {

			byte[] vbytes = new byte[1];
			ByteArrayOutputStream vOutNoSTDByteArrayOutputStream = new ByteArrayOutputStream();
			while (outputXML.read(vbytes) != -1) {
				vOutNoSTDByteArrayOutputStream.write(vbytes);
			}
			vOutNoSTDByteArrayOutputStream.flush();
			vOutNoSTDByteArrayOutputStream.close();
			byte[] tOutNoSTDbytes = vOutNoSTDByteArrayOutputStream
					.toByteArray();

			InputStream tOutNoSTDStreamAnother = new ByteArrayInputStream(
					tOutNoSTDbytes);

			byte[] x2 = tOutNoSTDbytes;
			InputStream g_input2 = new ByteArrayInputStream(x2);
			tOutNoSTDStreamAnother = g_input2;

			// 获取文件大小
			int fileLength;
			InputStream d = new ByteArrayInputStream(x2);
			for (fileLength = 0; d.read() != -1; fileLength++)
				;
			mLogger.info("报文总长度:" + fileLength);
			int tPackHeadLength = fileLength;
			
			String tPackHeadLengthStr = null;
			
			PacketAnalyze tPacketAnalyze = new PacketAnalyze();
			tPackHeadLengthStr = tPacketAnalyze.getBackHeadData(baseInfo, tPackHeadLength);
			
			// 增加包头信息
			byte[] array = new byte[tPackHeadLengthStr.length()];
			
			int m = 0;

			// 包体长度
			byte arrayPackHeadLength[] = tPackHeadLengthStr.getBytes();
			
			for (int i = 0; i < array.length; i++) {
				if (i < arrayPackHeadLength.length) {
					array[m] = arrayPackHeadLength[i];
				}
				m++;
			}

			mLogger.info("包头总长度:" + tPackHeadLengthStr);

			outputStream = m_socket.getOutputStream();
			outputStream.write(array);
			// 增加包体信息
			// 增加socket别的方法
			byte[] x = (new YBTFun()).INSToByteArray(tOutNoSTDStreamAnother);
			outputStream.write(x);

			mLogger.info("socket向客户端返回信息完毕。");
			mLogger.info("交易完毕");
			mLogger.info("****************************华丽的分行线************************");

		} catch (IOException e) {
			mLogger.error("将信息返回客户端失败:" + e);
		} catch (MidplatException e) {
			mLogger.error("将信息返回客户端失败:" + e);
		} finally {
			try {
				outputStream.flush();
				outputStream.close();
				m_socket.close();
			} catch (IOException e) {
				mLogger.error("关闭Socket和输出流失败");
			}
		}
	}

 C客户端代码(因为底层通信封装过的,所以我这边只贴出来自己写的,但是问题是一样的代码):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

#define LOCALFILE "1.xml"

struct netinfo_t {
	char addr[16];
	int iPort;
};

int RecvBuffer(int tmpSocket,int* iLen,char* tmpBufferRecv)
{
	int iRecvCount = 0;
	char strLen[7] = "\0";
	int iCountAll = 0;
	int iOperaCount = 0;
	

	iRecvCount = recv(tmpSocket, strLen ,6 ,0);
	if(iRecvCount <= 0)
	{
		close(tmpSocket);
		return -1;
	}
	iRecvCount = atoi(strLen);
	*iLen = iRecvCount;
 /*
  if(0 != readn(tmpSocket, tmpBufferRecv, *iLen)) {
      perror("rec");
			printf("error recv\n");
			close(tmpSocket);
			return -1;
  }
*/
	while(iCountAll < iRecvCount)
	{
		iOperaCount = recv(tmpSocket,tmpBufferRecv+iCountAll,iRecvCount-iCountAll,0);
		if(iOperaCount <= 0)
		{
      perror("rec");
			printf("error recv\n");
			close(tmpSocket);
			return -1;
		}
		iCountAll += iOperaCount;
	}	

	return 0;
}

int SendBuffer(int tmpSocket,int iLen,char* tmpSendBuffer)
{
	char strSendLen[10] = "\0";
	int iOperaCount = 0;
	sprintf(strSendLen,"%08d",iLen);
	int iCountAll = 0;

	iOperaCount = send(tmpSocket, strSendLen, 8, 0);
	if(0 >= iOperaCount)
	{
		close(tmpSocket);
		return -1;
	}

	while(iCountAll < iLen)
	{
		iOperaCount = send(tmpSocket, tmpSendBuffer + iCountAll, iLen-iCountAll, 0);
		if(0 >= iOperaCount)
		{
			close(tmpSocket);
			return -1;
		}
		iCountAll += iOperaCount;
	}

	return 0;
}

int sockCnt(void *infor)
{
	int iSock;
	int iOn = 1;
	struct sockaddr_in stClient;
	int iLen = sizeof(stClient);
	int iPort;
	struct netinfo_t *netinfor = (struct netinfo_t *)infor;
	int bufferLen;
	char tmpSendBuffer[20480] = "\0";
	FILE *fp;
	int FILELen;
	int iReadCount = 0;
	int iRetCount = 0;
	char *pFileBuffer;
	
	iPort = netinfor->iPort;
	memset(&stClient, 0, iLen);
	stClient.sin_family = AF_INET;
	stClient.sin_addr.s_addr = inet_addr(netinfor->addr);
	stClient.sin_port = htons(iPort);
	
	if((iSock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
		printf("create socket error\n");
		return -1;
	}
	
	/*set socket option*/
	if (setsockopt(iSock, SOL_SOCKET, SO_REUSEADDR,
		              &iOn, sizeof(iOn)) < 0) {
		printf("Socket Server Reuse Address Fail\n");
		return -1;
	}
	
	/*connect call*/
	if(connect(iSock, (struct sockaddr *)&stClient, iLen) < 0) {
		perror("connect:\n");
		printf("connect remote server error!\n");
		return -1;
	}
	
	if((fp = fopen(LOCALFILE, "rb")) == NULL) {
		printf("file open error!\n");
		return -1;
	}
	fseek(fp, 0L, SEEK_END);
	FILELen = ftell(fp);
	fseek(fp, 0L, SEEK_SET);
	printf("---->file length:%d\n",FILELen);
	pFileBuffer = (char *) malloc(FILELen + 1);
	
	while (iReadCount < FILELen) {
		iRetCount =
			fread(pFileBuffer + iReadCount, sizeof(unsigned char),
			      FILELen - iReadCount, fp);
		iReadCount += iRetCount;
		if(iRetCount < 0) {
			printf("fread error!\n");
			fclose(fp);
			return -1;
		}
	}
	printf("---->file:%s\n",pFileBuffer);
	fflush(fp);
	
	pFileBuffer[FILELen] = 0x00; 
	
		SendBuffer(iSock, FILELen, pFileBuffer);
		
		RecvBuffer(iSock, &bufferLen, tmpSendBuffer);
		printf("bufferLen[%d] tmpSendBuffer[%s] ----->tmpSendBuffer[%x]\n", bufferLen, tmpSendBuffer, tmpSendBuffer);
	close(iSock);
	return;
}

我这边测试用的java客户端代码:

public String send() throws Exception {
		String rv = "";
		InputStream is = null;
		String funcflag = res.getString("PackageHead");
		String filename = res.getString("PackageFile");

		try {
			is = new FileInputStream(filename);
			byte[] sendbuf = getBytes(is);// 整个交易信息

			String headlength = ""; // 得到头长度

			if (funcflag == null || funcflag.length() > 7)
				throw new Exception("获取交易码出错!");

			headlength = fillRightStr(String.valueOf(sendbuf.length), 6, " ");
			headlength += fillRightStr(funcflag, 7, " ");

			byte[] sendhead = headlength.getBytes(CHARSET);// 发送报文的头部
			byte[] send = new byte[sendbuf.length + sendhead.length];// 发送报文缓冲区

			System.arraycopy(sendhead, 0, send, 0, sendhead.length);// 将头拷贝到发送报文中
			System.arraycopy(sendbuf, 0, send, sendhead.length, send.length
					- sendhead.length);// 将报文体拷贝到发送报文中

			ip = res.getString("YBTHost");
			port = Integer.parseInt(res.getString("YBTPort"));
			System.out.println("发送数据到主机:" + ip + ", 端口:" + port);

			System.out.println("请求报文:");
			System.out.println(new String(sendbuf, CHARSET));

			// 新建Socket通信
			Socket socket = new Socket(ip, port);

			// 通信输出字节流
			OutputStream out = socket.getOutputStream();
			out.write(send);
			out.flush();

			// 开始接收数据
			byte[] buf = new byte[1];
			InputStream in = socket.getInputStream();
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			while (in.read(buf) != -1)
				baos.write(buf);

			byte[] bytes = baos.toByteArray();

			byte[] back = new byte[bytes.length - sendhead.length];
			System.arraycopy(bytes, sendhead.length, back, 0, bytes.length
					- sendhead.length);

			baos.flush();
			baos.close();
			is.close();

			rv = new String(back, "GBK");
		} catch (Exception e) {
			throw new Exception(e);
		}

		return rv;
	}

	private String fillRightStr(String str, int length, String fill) {
		int fillLength = length - str.length();
		for (int i = 0; i < fillLength; i++)
			str += fill;
		return str;
	}

 抓包情况:

18:41:34.219385 IP local.50290 > server.8602: S 3262906674:3262906674(0) win 65535 <mss 1460>
18:41:34.241106 IP server.8602 > local.50290: S 1854668494:1854668494(0) ack 3262906675 win 5840 <mss 1460>
18:41:34.241128 IP local.50290 > server.8602: . ack 1 win 65535
18:41:35.826513 IP local.50290 > server.8602: P 1:53(52) ack 1 win 65535
18:41:35.846242 IP server.8602 > local.50290: . ack 53 win 5840
18:41:36.555608 IP local.50290 > server.8602: P 53:1611(1558) ack 1 win 65535
18:41:36.588355 IP server.8602 > local.50290: . ack 1513 win 8760
18:41:36.588555 IP server.8602 > local.50290: . ack 1611 win 8760
18:41:36.664539 IP server.8602 > local.50290: P 1:14(13) ack 1611 win 8760
18:41:36.664738 IP server.8602 > local.50290: R 14:14(0) ack 1611 win 8760

 可以看到服务端返回reset包之后,通信终端。

麻烦各位看一下。

 

2013年5月15日 19:49
目前还没有答案

相关推荐

    计算机网络实验二- Socket通信编程与传输协议分析

    计算机网络实验中的Socket通信编程与传输协议分析是一个深入理解TCP/IP协议栈中传输层工作原理的重要实践环节。在这个实验中,学生们将通过编程实践来掌握Socket接口的使用,理解TCP的连接建立、数据传输和连接关闭...

    检测tcp端口是否被占用

    在IT行业中,网络通信是至关重要的一个环节,TCP(Transmission Control Protocol)作为互联网协议栈中的主力,负责在两台计算机之间建立可靠的数据传输连接。在进行网络编程时,经常需要检查特定的TCP端口是否被...

    java端口扫描器

    7. **Socket编程**:Java的Socket类是网络编程的基础,它提供了一种在两台机器间建立可靠、双向通信的方法。在端口扫描器中,Socket用于尝试建立连接,通过异常处理来判断端口是否开放。 8. **并发处理**:为了提高...

    java端口扫描.zip

    Java端口扫描是一种技术,主要用于检测网络上的主机开放了哪些通信端口,这些端口是计算机服务对外提供功能的窗口。在本项目中,我们有一个名为"java端口扫描.zip"的压缩包,其中包含了一个Java编写的端口扫描小工具...

    JAVA写的端口扫描程序

    JAVA的`java.net.Socket`类用于创建TCP连接,`SocketInputStream`和`SocketOutputStream`用于读写数据。 4. **端口扫描原理**:端口扫描通常通过发送SYN包(TCP三次握手的一部分)来测试端口是否开放,如果收到SYN+...

    Java.Source.Scan

    Java的`java.net.Socket`和`java.net.DatagramSocket`类分别用于TCP和UDP的连接与通信。 在源代码中,我们可以预期包含以下几个关键部分: 1. **目标主机和端口范围的定义**:程序需要指定要扫描的主机IP地址和...

    java中的connection reset 异常处理分析

    在本文中,我们将深入探讨这种异常的处理和分析,特别是与Java中的Socket通信相关的方面。 首先,`ConnectionResetException`是Java中与网络连接异常相关的错误类型,它通常在尝试读取或写入一个已经关闭或重置的...

    简单的端口扫描器

    在Java中实现端口扫描,可以使用`java.net.Socket`类或者`java.nio`包中的非阻塞I/O功能。以下是一个基本的TCP端口扫描器示例: ```java import java.io.IOException; import java.net.InetSocketAddress; import ...

    端口扫描器

    以上就是关于“Java版端口扫描器”的核心知识点,涵盖了从基础的Java编程、Swing GUI设计到Socket网络通信和端口扫描原理等多个方面。通过学习和理解这个项目,开发者可以提升在网络编程和GUI开发方面的技能。

    利用多线程基于TCP扫描目的主机端口程序--课程设计(含课程报告和代码).rar

    在IT领域,网络通信是核心部分之一,而端口扫描是网络管理员和安全专家常用的工具,用于检测远程或本地系统开放的服务和端口。本课程设计的主题是“利用多线程基于TCP扫描目的主机端口程序”,这涉及到计算机网络、...

    Android网络编程-TCP协议.pdf

    开发者需要知道如何使用Java的Socket类或者OkHttp等库来实现TCP通信,同时处理连接建立、数据传输和连接关闭等过程。熟悉TCP协议的工作原理和特性,可以帮助开发者更有效地构建稳定、高效的网络应用。

    T/TCP实现:TCP输出

    TCP(Transmission Control Protocol)是一种面向连接的、...在Java网络编程中,理解TCP和T/TCP的工作原理至关重要,特别是对于开发涉及Socket通信的应用。掌握这些概念可以帮助开发者编写出更高效、更健壮的网络应用。

    API实现检测IP存活,调用系统API练手

    例如,在Python中,可以使用`os.system()`调用系统`ping`命令,或者使用`socket`库直接发送ICMP、TCP或UDP数据包。在Java中,可以使用`java.net.InetAddress.isReachable()`方法。对于更底层的操作,可能需要使用如C...

    TCP三次握手和四次挥手面试题 249 - 330

    控制位包括 ACK、RST、SYN 和 FIN 等字段,分别用于确认应答、重置连接、建立连接和断开连接。 TCP 协议的必要性 为什么需要 TCP 协议?IP 层是不可靠的,它不能保证网络包的交付、顺序交付和数据的完整性。因此...

    p124 - p163 TCP三次握手 四次挥手原理解析

    控制位包括 ACK、RST、SYN、FIN 等,ACK 表示确认应答的字段变为有效,RST 表示 TCP 连接中出现异常必须强制断开连接,SYN 表示希望建立连接,并在其“序列号”的字段进行序列号初始值的设定,FIN 表示今后不会再有...

    商业编程-源码-一个简单的端口扫描程序题.zip

    - **Java**:跨平台,可以使用Java NIO进行端口扫描。 - **Go**:并发性能强,适合构建快速扫描工具。 4. **源码分析**: - 本示例可能包含用特定语言编写的端口扫描程序,涉及网络套接字编程,如创建socket,...

Global site tag (gtag.js) - Google Analytics