可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm developing an application using Winsock in C++. I have a 200-byte-length char array for sending strings over the socket.
My problem is when sending messages which are larger than the char array, so I decided to send them in multiple chunks but I have no idea how to do it.
For sending and receiving the data, I'm using the regular send()
and recv()
functions:
recv(client, buffer, 200, NULL);
send(client, buffer, 200, NULL);
Update
I have a struct:
struct Pack
{
unsigned int senderId;
char str[200];
}
before sending I convert the struct
to char array.
Pack pk;
strcpy_s(pk.str, 200, "Some text to send.\0");
pk.senderId = 1 // user id
char *buffer = (char*)pk;
If the string size if larger than 200 the strcpy_s() crashes.
回答1:
You have an example in Beej's Guide to Network Programming:
7.3. Handling Partial send()s
Remember back in the section about send(), above, when I said that
send() might not send all the bytes you asked it to? That is, you want
it to send 512 bytes, but it returns 412. What happened to the
remaining 100 bytes?
Well, they're still in your little buffer waiting to be sent out. Due
to circumstances beyond your control, the kernel decided not to send
all the data out in one chunk, and now, my friend, it's up to you to
get the data out there.
You could write a function like this to do it, too:
int sendall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = send(s, buf+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 onm failure, 0 on success
}
EDIT: As pointed out by @alk, replace all those int
s with ssize_t
- The type returned by send()
回答2:
If you're sending or receiving UDP packets, then there is no way around it; you'll need a buffer big enough to hold the entire packet. Fortunately, in most cases you don't want to send or receive UDP packets bigger than around 1500 bytes anyway, (since that is the largest packet an Ethernet card can send without fragmenting it into smaller packets, and generally you want to avoid fragmentation if possible).
For TCP, keep in mind that you are sending/receiving a stream of bytes, rather than a series of individual packets, and that so the sizes you pass to send() and recv() will not generally correspond to the sizes of the network packets anyway. That means that calling send() 6 times, each with 100 bytes of data, isn't much different from calling send() 1 time with 600 bytes of data, and so on. As others have noted, you do have to carefully check the return value of each send() and recv() call to see how many bytes were actually sent or received, since the number sent/received can (and will) sometimes be smaller than the number of bytes you requested. You need to know how many bytes were actually sent in order to know which bytes are appropriate to send on the next call, and you need to know how many bytes were actually received in order to know how many bytes are now valid in your receive-buffer.
回答3:
You need buffering on both ends.
When you send
something, you are not assured that all your buffer would be sent. The send(2) syscall may return a partial byte count.
Likewise, when your recv
something, the byte stream may be partial. The recv(2) syscall may return a partial byte count.
You probably need some event loop (e.g. above poll(2)) to mix both sending and receiving.
TCP/IP does not guarantee that a given send
(in the emitter machine) correspond to one recv
(in the receiving machine): the byte stream might have been chunked into arbitrary pieces in between (e.g. by routers). See also this.
回答4:
Send the message piece by piece. You can only send pieces as large as the send buffer size, so you need to remember how much you have sent and how much remains; then you can use a loop to do what is required:
int bufferSize = 200;
int messageLength = 442; // or whatever
int sendPosition = 0;
while (messageLength) {
int chunkSize = messageLength > bufferSize ? bufferSize : messageLength;
memcpy(buffer, message + sendPosition, chunkSize);
chunkSize = send(client, buffer, chunkSize, NULL);
messageLength -= chunkSize;
sendPosition += chunkSize;
}
Of course you could simply send from message
instead of making a needless copy to buffer
first, but I am just illustrating the concept here.
Your receiving code would then possibly need to assemble the message in its entirety before being able to process it, but that really depends on the protocol you have designed.