Greg, thanks for responding. I have a client/server application suite built using J2SE. The two applications communicate using HTTP. The client connects to the server using the high-level URL and HttpURLConnection classes. The server listen for and services client requests using the low-level ServerSocketChannel and SocketChannel classes. The problem I'd like some advice on occurs when the server tries to read the content of a client's PUT (or POST) request. ...etc...
Does the server look like it's getting a chunked Content-Transfer-Encoding header from the client? If so, then you have to implement the chunked protocol. I thought of this mainly because of this statement:
* I can see from dumping the data to a console window that the content being received is the end part of what is being sent. Stated the other way, the part of the text that I'm sending that is not being received is the beginning. So if the text being sent consists of 100 lines, for example, I'm receiving something like the final 60 lines of that text on the receiving end.
The headers that go out with the content are as follows...
content-type: text/menu Cache-Control: no-cache Pragma: no-cache User-Agent: Java/1.4.2_09 Host: 192.168.0.104:55914 Connection: keep-alive Content-Length: 15932 I'm also wondering if the size of the POST or PUT content has an effect on whether it works or not. Do smaller transfers work? Do they omit the same size of initial material? If so, I'd guess that something isn't being buffered or sent properly on the client. The Sun-standard HttpURLConnection is extremely limited in what it can POST or PUT, and I don't recall how well-behaved it is if you exceed its limited capabilities.
Sorry, I meant to mention in my initial posting that this error occurs with content sizes as short as 128 bytes. (Maybe smaller, but 128 was the smallest test I've run so far.) I've also tried my "real world" 15K as well as 1K, 2K and 5K and I always receive only part of the data. You could use the 'tcpdump' command to see if the client really is sending what it should be. See 'man tcpdump' in Terminal.
Good point. I'll try that tomorrow and post what I find. Another possibility is that something is screwy with the Channel support on server-sockets, or something in that vein. Or that you're simply not using the ServerSocketChannel and/or its I/O streams correctly, though I can't tell without all the code.
This problem shows up in just the second HTTP request my application makes. I guess another point worth making is that the request that I'm having a problem with works fine in all other respects if I don't open an OutputStream on the client or InputStream on the server. I realize your server-side code works when run on XP, but you don't say how many CPUs you have, or what machine, or what OS versions, all of which may be relevant. In short, it might work on XP by accident, or by a side-effect of the platform's implementation. Or it might fail on Mac OS X for side-effect ereasons.
The XP machines I have are both single CPU (single core) P4-HT. One runs at 1.8GHz, the other at 2.3GHz. They're both running XP-P2. The JVM I run under XP is 1.4.2_06. I'm running MacOSX 10.4.4 on a dual G5 2GHz with 2GB of memory. The problems I'm having when MacOSX is involved occur when I'm running both the stock 1.4.2 JVM and the final candidate of 5.0. Since it's easy to use the non-Channel ServerSocket class to listen and accept() new connections, I suggest writing a simple server using that older API and see if it works or not against your existing client. There are many examples you can crib ServerSocket code from, which a little googling should turn up. I've used that API many times and it works consistently on Mac OS X, either same machine or different ones, with or without CR-LF's, interop with XP or not, and with or without HTTP.
Generating sample code is something I was hoping to avoid, but may have to do if it's not otherwise obvious what's going on. As I'm sure you know, the code-base of real applications are often much more involved than sample code needs to be, even if most of the code is doing unrelated tasks. The trick to writing an HTTP server is you have to be fastidious in how you implement the HTTP protocol. It's easy to get it wrong, and even tiny mistakes or omissions can have big consequences. Also, it's a lot easier to implement HTTP 1.0 than 1.1, and when I've done HTTP servers in the past, that's always where I start.
I know one thing that has worried me from the start is that the client code is using high-level HTTP connections while the server code is using low-level sockets. I was worried that getting these two sides to talk to each other might not be easy. As a cross-check, have your client send a POST to Personal Web Sharing on Mac OS X, which runs the Apache server. Then hook it up to a simple CGI diagnostic that tells you what it received. It's pretty easy to serve pages with Personal Web Sharing, and it's reasonably straightforward to configure it to run CGI's.
* The problem occurs when 1) the client is running under MacOSX and the server is running under Windows XP, 2) client = XP & server = Mac, or 3) client = Mac & server = Mac. The problem does not occur if both client and server are XP based -- whether on the same XP box or different ones.
Are you perhaps using println() to a socket? Or perhaps using readline() from a socket? If so, then the problem may be that you're not sending CR-LF line-terminators.
I'm not using println nor am I using Reader's. I'm converting my content data to a byte[] and then writing those bytes as a single call to the OutputStream's write() method. As on the reading side -- I get the Content-Length, create a properly sized byte[], then do a single read on the socket's InputStream's read() method. All the above is little more than guessing and conjecture. Posting small fragments of code tells nothing about the surrounding context, and in client-server communication, context is crucial.
If none of the suggestions works out, I suggest creating a well-isolated test-case that consistently exhibits the failure, and making it available as a URL. Then post the URL to the list. One possible side-effect is that the process of creating a well-isolated fail-case leads to a recognition of a subtle latent bug in one's original code. I've done that a few times, so ruthless simplication can have a reward.
If nothing I've said here rings a bell for anybody, then I'll post a sample case tomorrow or the next day.
Thanks again for your response.
- Sparky
|