大四中软实习笔记20130305

1 Winsock网络编程

1.1 TCP/IP网络的概念

应用层----我们的程序、数据
传输层----TCP/UDP  端口号      运沙子UDP   运机器TCP
网络层----IP  计算机---计算机 可以通信了
物理层----网卡 电压


1.2 TCP服务器端编程步骤
1 准备工作
确定使用Winsock的什么版本-----1.1

2 加载套接字
实现使用1.1版本-----同时还会,校验本机是否支持1.1版本

3 建立 侦听套接字(插座)-----在墙上装了1个电话插座

4 绑定-----就是宣布自己的 IP和端口号、自己的套接字

5 侦听----等待客户的连接请求

6 Accept响应客户的连接请求-------通信链路 通了;而且会返回1个  连接套接字

7 send/receive----都是通过 连接套接字


8 关闭   连接套接字

9 关闭 侦听套接字

10 卸载套接字

 


1.3 TCP服务器端编程步骤---翻译为C语言
1 准备工作
确定使用Winsock的什么版本-----1.1
增加头文件
#include <WINSOCK2.H>

增加lib库
ws2_32.lib

 

2 加载套接字
实现使用1.1版本-----同时还会,校验本机是否支持1.1版本
int WSAStartup (
  WORD wVersionRequested,  //申请的版本号,如1.1,但要用2个字节的整型数来表示,所以填写257。            ---输入参数
  LPWSADATA lpWSAData          //这是地址类型,指向了1个结构体空间。该函数执行后,会修改该结构体数据。 ---输出参数
);
代码:
    WSADATA wsadata;
    LPWSADATA lpWSAData=&wsadata;
    WSAStartup(257,lpWSAData);

3 建立 侦听套接字(插座)-----在墙上装了1个电话插座
SOCKET socket_listen=socket(AF_INET,SOCK_STREAM,0);

 

4 绑定-----就是宣布自己的 IP和端口号、自己的套接字
    struct sockaddr_in addr_b;
    addr_b.sin_addr.S_un.S_addr=inet_addr("172.18.23.200");
    addr_b.sin_port=6588;
    addr_b.sin_family=AF_INET;
    struct sockaddr * addr=(struct sockaddr *)&addr_b;
    bind(socket_listen,addr,sizeof(SOCKADDR));
   


5 侦听----等待客户的连接请求
    listen(socket_listen,4);
注意:4代表在线用户不能超过4个。
   

6 Accept响应客户的连接请求-------通信链路 通了;而且会返回1个  连接套接字
    sockaddr_in addr_bb;
    sockaddr * addr_client=(sockaddr *)&addr_bb;
    int len=sizeof(sockaddr);
    SOCKET socket_connect=accept(socket_listen,addr_client,&len);
注意:
是阻塞函数,如果没有收到 任何客户的连接请求,程序会阻塞在这里。
阻塞不是绝对的,有前提----该阻塞的时候就阻塞,不该阻塞就不阻塞(如套接字库加载失败了,就不阻塞了;IP地址如果设错了,也不阻塞;网线断了,也不阻塞)。
如果,IP设置为127.0.0.1时,网线通时阻塞,不通时也阻塞。但为了使我们的服务器程序具有通用性,应该设置为127.0.0.1.

但不能设置为127.0.0.1,因为如果这样设置,别的的PC永远也连不到服务器了。所以,它只是用来进行本机测试用的。
所以,应该这样设置:
addr_b.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
但也有问题,即网线通或不通,都会阻塞。

 

 


7 send/receive----都是通过 连接套接字
    char buf_recv[1000]={'\0'};
    recv(socket_connect,buf_recv,sizeof(buf_recv)-1,0);
    //strlen(buf_recv);
    buf_recv[999]='\0';
    printf("%s\n",buf_recv);
注意:
recv是阻塞函数-----网络通,而且收不大任何数据时阻塞   
所以不阻塞时有2种情况:
1 收到数据了,就不阻塞了,函数将运行结束,而且有返回值。
2 如果收到数据了,返回值是数据的字节数。
3 但此时,如果客户端的网线断了,服务器是无法知道的(因为服务器的网口是通的),一直阻塞下去
4 如果客户端执行了关闭套接字,那么服务器端的recv会返回0(但不表示收到了0字节,而表示侦听套接字链路收到了客户端的关闭套接字请求)),此时,就又不阻塞了。
5 如果recv返回-1,则服务器端,肯定收到了客户端的关闭套接字(请求)---通过侦听套接字的链路.
6 如果客户端没有关闭套接字,而客户端的网线断了,则服务器是不知道的,所以recv会一直阻塞。
7 如果客户端没有关闭套接字,但客户端程序退出了,则服务器的recv会返回-1(相当于收到了客户端的关闭套接字请求).


解决办法:增加心跳检测代码


   
   

8 关闭   连接套接字
    closesocket(socket_connect);

9 关闭 侦听套接字
closesocket(socket_listen);


10 卸载套接字库
    WSACleanup();

代码:

//服务器端
#include <stdio.h>
#include <string.h>
#include <WINSOCK2.H>

int main()
{
    WSADATA wsadata;
    LPWSADATA lpWSAData=&wsadata; 
    WSAStartup(257,lpWSAData);

    SOCKET socket_listen=socket(AF_INET,SOCK_STREAM,0);

    
    struct sockaddr_in addr_b;
    addr_b.sin_addr.S_un.S_addr=inet_addr("172.18.23.200"); 
    addr_b.sin_port=6588;
    addr_b.sin_family=AF_INET;
    struct sockaddr * addr=(struct sockaddr *)&addr_b;
    bind(socket_listen,addr,sizeof(SOCKADDR));

    listen(socket_listen,4);

    sockaddr_in addr_bb;
    sockaddr * addr_client=(sockaddr *)&addr_bb;
    int len=sizeof(sockaddr);
    SOCKET socket_connect=accept(socket_listen,addr_client,&len);


    char buf_recv[1000]={'\0'};
    recv(socket_connect,buf_recv,sizeof(buf_recv)-1,0);
    //strlen(buf_recv);
    buf_recv[999]='\0';
    printf("%s\n",buf_recv);

    closesocket(socket_connect);

    closesocket(socket_listen);

    WSACleanup();


    return 0;
}

1.4 TCP客户端编程步骤
1 准备工作
头文件、lib文件

2 加载套接字库
一样
    WSADATA wsadata;
    LPWSADATA lpWSAData=&wsadata;
    WSAStartup(257,lpWSAData);
   
3 建立  客户端套接字
一样
SOCKET socket_client=socket(AF_INET,SOCK_STREAM,0);


4 发生连接请求给服务器
connect()
不一样
struct sockaddr_in addr_b;
    addr_b.sin_addr.S_un.S_addr=inet_addr("172.18.23.200");
    addr_b.sin_port=6588;
    addr_b.sin_family=AF_INET;
    struct sockaddr * addr=(struct sockaddr *)&addr_b;
    connect(socket_client,addr,sizeof(sockaddr));

5 发生数据
send()
一样
char buf_send[]="hello,我是客户端!";
send(socket_client,buf_send,strlen(buf_send)+1,0);


6 关闭套接字
一样
closesocket(socket_client);

7 卸载套接字库
一样
WSACleanup();


1.5 代码示例
//客户端:

#include <stdio.h>
#include <string.h>
#include <WINSOCK2.H>

int main()
{
    WSADATA wsadata;
    LPWSADATA lpWSAData=&wsadata; 
    WSAStartup(257,lpWSAData);
    
    SOCKET socket_client=socket(AF_INET,SOCK_STREAM,0);

    struct sockaddr_in addr_b;
    addr_b.sin_addr.S_un.S_addr=inet_addr("172.18.23.200"); 
    addr_b.sin_port=6588;
    addr_b.sin_family=AF_INET;
    struct sockaddr * addr=(struct sockaddr *)&addr_b;
    connect(socket_client,addr,sizeof(sockaddr));

    char buf_send[]="hello,我是客户端!";
    send(socket_client,buf_send,strlen(buf_send)+1,0);

    char buf_recv[1000]={'\0'};
    recv(socket_client,buf_recv,sizeof(buf_recv)-1,0);
    printf("%s\n",buf_recv);
    

    closesocket(socket_client);
    
    
    WSACleanup();
    
    
    return 0;
}

 

服务器端:

#include <stdio.h>
#include <string.h>
#include <WINSOCK2.H>

int main()
{
    WSADATA wsadata;
    LPWSADATA lpWSAData=&wsadata; 
    WSAStartup(257,lpWSAData);

    SOCKET socket_listen=socket(AF_INET,SOCK_STREAM,0);

    
    struct sockaddr_in addr_b;
    addr_b.sin_addr.S_un.S_addr=inet_addr("172.18.23.200"); 
    addr_b.sin_port=6588;
    addr_b.sin_family=AF_INET;
    struct sockaddr * addr=(struct sockaddr *)&addr_b;
    bind(socket_listen,addr,sizeof(SOCKADDR));

    listen(socket_listen,4);

    sockaddr_in addr_bb;
    sockaddr * addr_client=(sockaddr *)&addr_bb;
    int len=sizeof(sockaddr);
    SOCKET socket_connect=accept(socket_listen,addr_client,&len);


    char buf_recv[1000]={'\0'};
    recv(socket_connect,buf_recv,sizeof(buf_recv)-1,0);
    //strlen(buf_recv);
    //buf_recv[999]='\0';
    printf("%s\n",buf_recv);

    char buf_send[]="我是服务器!";
    send(socket_connect,buf_send,strlen(buf_send)+1,0);

    closesocket(socket_connect);

    closesocket(socket_listen);

    WSACleanup();
    //system("pause");


    return 0;
}

1.6 改进后的代码
服务器端:
#include <stdio.h>
#include <string.h>
#include <WINSOCK2.H>

int main()
{
    WSADATA wsadata;
    LPWSADATA lpWSAData=&wsadata; 
    WSAStartup(257,lpWSAData);

    SOCKET socket_listen=socket(AF_INET,SOCK_STREAM,0);

    
    struct sockaddr_in addr_b;
    //addr_b.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); 
    addr_b.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
    addr_b.sin_port=htons(6588);
    addr_b.sin_family=AF_INET;
    struct sockaddr * addr=(struct sockaddr *)&addr_b;
    bind(socket_listen,addr,sizeof(SOCKADDR));

    int flag=listen(socket_listen,4);

    sockaddr_in addr_bb;
    sockaddr * addr_client=(sockaddr *)&addr_bb;
    int len=sizeof(sockaddr);
    SOCKET socket_connect=4576;
    socket_connect=accept(socket_listen,addr_client,&len);


    char buf_recv[1000]={'\0'};
    int count=recv(socket_connect,buf_recv,sizeof(buf_recv)-1,0);
    //strlen(buf_recv);
    //buf_recv[999]='\0';
    printf("%s\n",buf_recv);

    char buf_send[]="我是服务器!";
    send(socket_connect,buf_send,strlen(buf_send)+1,0);

    closesocket(socket_connect);

    closesocket(socket_listen);

    WSACleanup();
    //system("pause");


    return 0;
}

客户端:
#include <stdio.h>
#include <string.h>
#include <WINSOCK2.H>

int main()
{
    WSADATA wsadata;
    LPWSADATA lpWSAData=&wsadata; 
    WSAStartup(257,lpWSAData);
    
    SOCKET socket_client=socket(AF_INET,SOCK_STREAM,0);

    struct sockaddr_in addr_b;
    addr_b.sin_addr.S_un.S_addr=inet_addr("172.18.23.200"); 
    addr_b.sin_port=htons(6588);
    addr_b.sin_family=AF_INET;
    struct sockaddr * addr=(struct sockaddr *)&addr_b;
    connect(socket_client,addr,sizeof(sockaddr));

    char buf_send[]="hello,我是客户端!";
    send(socket_client,buf_send,strlen(buf_send)+1,0);

    char buf_recv[1000]={'\0'};
    recv(socket_client,buf_recv,sizeof(buf_recv)-1,0);
    printf("%s\n",buf_recv);    
    
    closesocket(socket_client);    
    
    WSACleanup();
    //system("pause");
    
    return 0;
}

posted on 2013-03-07 09:31  冰河程序猿  阅读(254)  评论(0编辑  收藏  举报

导航