Đây là đơn giản, và ra khỏi đỉnh ngón tay của tôi, nhưng tôi nghĩ rằng một cái gì đó dọc theo những dòng sẽ làm việc ra:
template <unsigned BUF_SIZE>
struct Buffer {
char buf_[BUF_SIZE];
int len_;
Buffer() : buf_(), len_(0) {}
int read (int fd) {
int r = read(fd, buf_ + len_, BUF_SIZE - len_);
if (r > 0) len_ += r;
return r;
}
int capacity() const { return BUF_SIZE - len_; }
}
template <unsigned BUF_SIZE>
struct BufferStream {
typedef std::unique_ptr< Buffer<BUF_SIZE> > BufferPtr;
std::vector<BufferPtr> stream_;
BufferStream() : stream_(1, BufferPtr(new Buffer<BUF_SIZE>)) {}
int read (int fd) {
if ((*stream_.rbegin())->capacity() == 0)
stream_.push_back(BufferPtr(new Buffer<BUF_SIZE>));
return (*stream_.rbegin())->read(fd);
}
};
Trong một bình luận, bạn nói bạn muốn tránh tạo ra một bộ đệm char lớn. Khi sử dụng cuộc gọi hệ thống read
, thông thường sẽ hiệu quả hơn khi thực hiện một số lần đọc lớn thay vì nhiều lần đọc nhỏ. Vì vậy, hầu hết các triển khai sẽ lựa chọn không cho bộ đệm đầu vào lớn để đạt được hiệu quả đó. Bạn có thể triển khai một cái gì đó như:
std::vector<char> input;
char in;
int r;
while ((r = read(fd, &in, 1)) == 1) input.push_back(in);
Nhưng điều đó sẽ liên quan đến cuộc gọi hệ thống và ít nhất một byte được sao chép cho mỗi byte đầu vào. Ngược lại, mã tôi đưa ra tránh các bản sao dữ liệu thừa.
Tôi thực sự không mong đợi mã mà tôi đưa ra là giải pháp bạn sẽ áp dụng. Tôi chỉ muốn cung cấp cho bạn một minh họa về cách tạo ra một đối tượng tự mở rộng là khá không gian và thời gian hiệu quả. Tùy thuộc vào mục đích của bạn, bạn có thể muốn mở rộng nó hoặc viết của riêng bạn. Off đỉnh đầu của tôi, một số cải tiến có thể là:
- sử dụng
std::list
thay vào đó, để tránh vector thay đổi kích thước
- phép API một tham số để xác định có bao nhiêu byte để đọc
- sử dụng
readv
luôn luôn cho phép ít nhất BUF_SIZE
bytes (hoặc hơn BUF_SIZE
bytes) để đọc tại một thời điểm
Có. Khá nhiều người đã viết bộ đệm luồng kết nối với ổ cắm. Trong khi ban đầu họ có vẻ mát mẻ, ít nhất là từ những gì tôi đã nhìn thấy, họ hiếm khi làm việc tốt trong thực tế. Bạn (gần như) cần phải thêm một số loại hoạt động không đồng bộ (ví dụ, như ASIO) để làm cho nó hoạt động tốt. http://socketstream.sourceforge.net/, http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.html, v.v. –