2012年7月5日星期四

winsock C/S模型

;本人制作的一个最简单的网络示例程序。
;先运行服务器端程序,再运行客户端程序。
;made by correy
;QQ:112426112
;Email:leguanyuan@126.com
;Homepage:http://correy.webs.com
;欢迎网络高手指点。

;服务器端程序如下:
.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
include ws2_32.inc

includelib user32.lib
includelib kernel32.lib
includelib WS2_32.lib

.data
ip db "127.0.0.1",0
notice db "(服务器端显示)从一个客户端发来的信息已经收到,内容是:",0

.data?
ipwsadata WSADATA <>
ipsockaddr sockaddr_in <>
buffer db 256 DUP (?)
s dd ?
s2 dd ?

.code
start:
invoke WSAStartup,2,addr ipwsadata
invoke socket,AF_INET,SOCK_STREAM,0
mov s,eax

invoke inet_addr,addr ip
mov ipsockaddr.sin_addr,eax
mov ipsockaddr.sin_family,AF_INET
MOV ipsockaddr.sin_port,80

invoke bind,s,addr ipsockaddr,16
invoke listen,s,9
invoke accept,s,0,0
mov s2,eax
invoke recv,s2,addr buffer,sizeof buffer,MSG_PEEK
invoke MessageBox,0,addr buffer,addr notice,0

invoke closesocket,s
invoke WSACleanup
invoke ExitProcess,0
end start
;客户端程序如下:
.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include ws2_32.inc

includelib kernel32.lib
includelib WS2_32.lib

.data
correy db "made by correy",0
ip db "127.0.0.1",0

.data?
ipwsadata WSADATA <>
ipsockaddr sockaddr_in <>
buffer db 256 DUP (?)
s dd ?

.code
start:
invoke WSAStartup,2,addr ipwsadata
invoke socket,AF_INET,SOCK_STREAM,0
mov s,eax

invoke inet_addr,addr ip
mov ipsockaddr.sin_addr,eax
mov ipsockaddr.sin_family,AF_INET
MOV ipsockaddr.sin_port,80

invoke connect,s,addr ipsockaddr,16
invoke send,s,addr correy,sizeof correy,0

invoke closesocket,s
invoke WSACleanup
invoke ExitProcess,0
end start
;made at 2010.07.01
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;console版的tcp协议c/s模型通讯示例程序。
;made by correy
;QQ:112426112
;Email:leguanyuan@126.com
;Homepage:http://correy.webs.com
;不足之处:
;1.在客户端输入的数据过大,接近于缓存区的变量大小,会导致服务器端的程序显示有问题。
;2.输入数据的缓存处理等问题:在客户端输入一次以后,以后不输入按回车也会发送信息。
;3.没有统计在线客户数量的功能.
;4.没有显示在线客户的ip地址与端口的功能。
;客户端程序如下:
.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include ws2_32.inc

includelib kernel32.lib
includelib WS2_32.lib

.data
correy db "made by correy",0
ip db "127.0.0.1",0
conn db "连接成功!",0ah,0dh,0
notice db "请输入你要发送的内容,按回车键发送。",0ah,0dh,0
unc db "连接失败!看看服务端程序是否先运行。要退出请按回车键。",0
sended db "信息已经发送出去!按回车键继续发送",0
uns db "信息没有发送出去!要退出请按回车键。",0

.data?
ipwsadata WSADATA <>
ipsockaddr sockaddr_in <>
buffer db 256 DUP (?)
s dd ?
hstdin dd ?
hstdout dd ?
x dd ?

.code
start:

invoke GetStdHandle,-10
mov hstdin,eax
invoke GetStdHandle,-11
mov hstdout,eax
again:
invoke WSAStartup,2,addr ipwsadata
invoke socket,AF_INET,SOCK_STREAM,0
mov s,eax

invoke inet_addr,addr ip
mov ipsockaddr.sin_addr,eax
mov ipsockaddr.sin_family,AF_INET
MOV ipsockaddr.sin_port,80

invoke connect,s,addr ipsockaddr,16
cmp eax,-1
je uncon
invoke lstrlen,addr conn
invoke WriteFile,hstdout,addr conn,eax,0,0

invoke lstrlen,addr notice
invoke WriteFile,hstdout,addr notice ,eax,0,0
invoke ReadFile,hstdin,addr buffer,sizeof buffer,addr x,0

invoke send,s,addr buffer,sizeof buffer,0
cmp eax,-1
je unsend
invoke lstrlen,addr sended
invoke WriteFile,hstdout,addr sended,eax,0,0
invoke ReadFile,hstdin,addr buffer,sizeof buffer,addr x,0
jmp again
jmp exit

uncon:
invoke lstrlen,addr unc
invoke WriteFile,hstdout,addr unc,eax,0,0
invoke ReadFile,hstdin,addr buffer,sizeof buffer,addr x,0
jmp exit
unsend:
invoke lstrlen,addr uns
invoke WriteFile,hstdout,addr uns,eax,0,0
invoke ReadFile,hstdin,addr buffer,sizeof buffer,addr x,0

exit:
invoke closesocket,s
invoke WSACleanup
invoke ExitProcess,0
end start

;服务端程序如下:
.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include ws2_32.inc

includelib kernel32.lib
includelib WS2_32.lib

.data
ip db "127.0.0.1",0
notice db "从一个客户端发来的信息内容是:",0
correy db "made by correy",0ah,0dh,\
          "QQ:112426112",0ah,0dh,\
          "Email:leguanyuan@126.com",0ah,0dh,\
          "Homepage:http://correy.webs.com",0ah,0dh,\
          "本服务端程序同一时间只能运行一个,客户端程序可以运行多个。",0ah,0dh,0

.data?
ipwsadata WSADATA <>
ipsockaddr sockaddr_in <>
buffer db 256 DUP (?)
s dd ?
s2 dd ?
hstdin dd ?
hstdout dd ?

.code
start:

invoke GetStdHandle,-10
mov hstdin,eax
invoke GetStdHandle,-11
mov hstdout,eax
invoke WriteFile,hstdout,addr correy,sizeof correy-1,0,0

invoke WSAStartup,2,addr ipwsadata
invoke socket,AF_INET,SOCK_STREAM,0
mov s,eax

invoke inet_addr,addr ip
mov ipsockaddr.sin_addr,eax
mov ipsockaddr.sin_family,AF_INET
MOV ipsockaddr.sin_port,80

invoke bind,s,addr ipsockaddr,16
invoke listen,s,9
again:
invoke accept,s,0,0
mov s2,eax
invoke recv,s2,addr buffer,sizeof buffer,MSG_PEEK
invoke WriteFile,hstdout,addr notice,sizeof notice,0,0
invoke lstrlen,addr buffer
invoke WriteFile,hstdout,addr buffer,eax,0,0
jmp again

invoke closesocket,s
invoke WSACleanup
invoke ExitProcess,0
end start
;made at 2010.07.02
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
微软官方的程序如下:
通讯的端口为:27015

客户端程序如:

// http://msdn.microsoft.com/en-us/library/windows/desktop/ms737591(v=vs.85).aspx

#include "stdafx.h"

#define WIN32_LEAN_AND_MEAN //不定义这个,可能下面两行会出现问题.

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h> //用到:getaddrinfo getaddrinfo

#pragma comment (lib, "Ws2_32.lib")// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib

int __cdecl main(int argc, char **argv)
{
    if (argc != 2) {//在本机测试可以填写127.0.0.1 Validate the parameters
        printf("usage: %s server-name\n", argv[0]);
        return 1;
    }

    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);// Initialize Winsock
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    struct addrinfo hints;
    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    struct addrinfo *result = NULL;
    iResult = getaddrinfo(argv[1], "27015", &hints, &result);// Resolve the server address and port
    if ( iResult != 0 ) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    SOCKET ConnectSocket = INVALID_SOCKET;  
    for(struct addrinfo * ptr = result; ptr != NULL ;ptr = ptr->ai_next) // Attempt to connect to an address until one succeeds
    {      
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);// Create a SOCKET for connecting to server
        if (ConnectSocket == INVALID_SOCKET) {
            printf("socket failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return 1;
        }

        iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);// Connect to server.
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }

    char * sendbuf = "this is a test";
    iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );// Send an initial buffer
    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    iResult = shutdown(ConnectSocket, SD_SEND);// shutdown the connection since no more data will be sent
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    do // Receive until the peer closes the connection
    {
        char recvbuf[512] = {0};
        iResult = recv(ConnectSocket, recvbuf, sizeof (recvbuf), 0);//如果服务端繁忙这里会等待,如调试,一般这里是不会等待的.
        if ( iResult > 0 ) {
            printf("Bytes received: %d\n", iResult);
        } else if ( iResult == 0 ) {
            printf("Connection closed\n");
        } else {
            printf("recv failed with error: %d\n", WSAGetLastError());
        }
    } while( iResult > 0 );

    closesocket(ConnectSocket);// cleanup
    WSACleanup();
    return 0;
}

服务端程序如下:

// http://msdn.microsoft.com/en-us/library/windows/desktop/ms737593(v=vs.85).aspx

#include "stdafx.h"

#undef UNICODE

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>

#pragma comment (lib, "Ws2_32.lib")// Need to link with Ws2_32.lib

int __cdecl main(void)
{
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);// Initialize Winsock
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    struct addrinfo hints;
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    struct addrinfo * result = NULL;
    iResult = getaddrinfo(NULL, "27015", &hints, &result);// Resolve the server address and port
    if ( iResult != 0 ) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    SOCKET ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);// Create a SOCKET for connecting to server
    if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);// Setup the TCP listening socket
    if (iResult == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    freeaddrinfo(result);

    iResult = listen(ListenSocket, SOMAXCONN);//会弹出"Windows 安全警报"提示框。
    if (iResult == SOCKET_ERROR) {
        printf("listen failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    SOCKET ClientSocket = accept(ListenSocket, NULL, NULL);//这里会等待. Accept a client socket
    if (ClientSocket == INVALID_SOCKET) {
        printf("accept failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    closesocket(ListenSocket);// No longer need server socket

    do // Receive until the peer shuts down the connection
    {
        char recvbuf[512] = {0};
        iResult = recv(ClientSocket, recvbuf, sizeof(recvbuf), 0);//如果没有消息,这里会等待.
        if (iResult > 0) {
            printf("Bytes received: %d\n", iResult);
            int iSendResult = send( ClientSocket, recvbuf, iResult, 0 );// Echo the buffer back to the sender
            if (iSendResult == SOCKET_ERROR) {
                printf("send failed with error: %d\n", WSAGetLastError());
                closesocket(ClientSocket);
                WSACleanup();
                return 1;
            }
            printf("Bytes sent: %d\n", iSendResult);
        } else if (iResult == 0) {
            printf("Connection closing...\n");
        } else  {
            printf("recv failed with error: %d\n", WSAGetLastError());
            closesocket(ClientSocket);
            WSACleanup();
            return 1;
        }
    } while (iResult > 0);

    iResult = shutdown(ClientSocket, SD_SEND);// shutdown the connection since we're done
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return 1;
    }

    closesocket(ClientSocket);// cleanup
    WSACleanup();
    return 0;
}

没有评论:

发表评论