recv和recvfrom都是用來接受來自的網路的資料。來看看它們的原型:
int recv(
SOCKET {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">s,
char FAR *{
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">buf,
int {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">len,
int {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">flags
);
int recvfrom(
SOCKET {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">s,
char FAR* {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">buf,
int {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">len,
int {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">flags,
struct sockaddr FAR *{
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">from,
int FAR *{
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">fromlen
);
這是在windows下面的定義。在linux下面的定義只是將SOCKET改成int,那麼在linux下面的原型是這樣:
int recv(
int {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">s,
char FAR *{
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">buf,
int {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">len,
int {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">flags
);
int recvfrom(
int {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">s,
char FAR* {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">buf,
int {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">len,
int {
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">flags,
struct sockaddr FAR *{
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">from,
int FAR *{
function onclick()
{
function onclick()
{
showTip(this)
}
}
}">fromlen
);
其實要是看看windows中SOCKET的定義,就知道它們幾乎是完全相同了,為什麼是幾乎?因為還是有點小區別,linux下面是int類型,而windows下面是unsigned int。下面就是windows中SOCKET的定義:
typedef UINT_PTR SOCKET;
typedef unsigned int UINT_PTR, *PUINT_PTR;
插一句,在linux下面這裡的int s, 其實代表的是檔案描述符。在linux中所有的裝置,如磁碟,光碟機,U盤甚至我們這裡的討論的網路也都被看作是檔案。
我們看看這兩個函數在功用上的共同點和不同點:
共同點:
1. 都是用來接受來自網路的資料
2. 都可以 接受連線導向的流式通訊端的 和 接受不需連線的資料通訊端 的資料
3. 在成功接受到資料後,傳回值都是實際接受的位元組數; 通訊端關閉時,返回都為0; 接受出錯時,windows下面都返回SOCKET_ERROR , linux下面都返回-1, 其實你要是感興趣可以查看SOCKET_ERROR 定義,它的值也是-1;
關於這裡的“通訊端關閉”需要注意,2個函數在用在流式通訊端和資料通訊端時,通訊端表示的含義不一樣,前者表示用戶端通訊端,而後者表示的是自己的通訊端。
4. 如果通訊端為阻塞的,在系統緩衝中沒有資料的情況下,都將阻塞;如果通訊端為非阻塞的,在系統緩衝中沒有資料的情況下,都將立即返回,傳回值在linux下為-1, errno被設定為EWOULDBLOCK,在windows下面返回SOCKET_ERROR, 通過WSAGetLastError返回WSAEWOULDBLOCK.
5. 如果用在流式通訊端,則2者的操作是:將已在核心緩衝區的資料拷貝到應用程式自己的緩衝區,拷貝的最大的長度為調用函數時傳入的緩衝區的長度,注意這裡的長度不一定等於實際緩衝區的長度,可以小於緩衝區的長度,但是絕對不能大於,為什麼不能大於,也許你比我更清楚。例如下面這段代碼:
char szRecvBuf[1024] = { 0 };
recv( sockServer, szRecvBuf, 256, 0 );
這裡雖然定義的緩衝區的長度為1024但是接受的時候只用其中的256. 如果核心緩衝區當時有10個位元組,那麼這次調用立刻返回,szRecvBuf被填充了10位元組,傳回值是10。 如果核心緩衝區有1500個位元組,那麼szRecvBuf將被填充256個位元組,傳回值就是256.
如果是資料通訊端,在核心緩衝區中的資料小於要求長度(這裡是256)的情況下,和流式通訊端結果一樣。但是大於的情況就不一樣了,首先將填充256到szRecvBuf中,並且產生一個WASEMSGSIZE的錯誤,並且剩下的部分被丟棄。假如核心緩衝區的資料為1000位元組,那麼前面的256被填充到szRecvBuf中,後面的1000-256將被丟棄。
recvfrom的執行效果也是同樣的。
上面的結論是結合msdn和實際的測試得出的。
recvfrom的實際效果也是這樣。
不同點:
1. 函數參數不一樣
未完待續...