Socket通信程序设计-网络实验4

来源:互联网 发布:学电脑编程续学校 编辑:程序博客网 时间:2024/05/01 21:11

3.实验指导

(1)什么是Socket

     Socket(套接字)是当前最流行的网络编程接口(网络编程的API)。Socket使用网络层的IP地址和传输层的端口号进行数据交换

(2) 常用Socket类型

  1、流式套接字(SOCK_STREAM),基于TCP协议,提供面向连接的、可靠的数据传输服务

  2、数据报套接字(SOCK_DGRAM),基于UDP协议,提供无连接的、不可靠的数据传输服务

  3、原始套接字(SOCK_RAW),提供对网络层协议的访问,可以保存IP数据包中完整的头部,前两者不保留,只是存储或转发

(3) TCP编程模式

(4) Server端程序设计要点

①相关对象的声明;

②启动监听;

③接受Client端连接请求,建立与Client端的连接;

④流式Socket上的数据接收;

⑤流式Socket上的数据发送;

⑥释放资源.

(5) Client端程序设计要点   Client端的程序设计与Server端有许多相似之处。差异主要在建立连接时,服务器端处于监听状态,而客户端要发起连接请求.一旦连接建立后,双方就将平等地发送与接收数据.

•根据代码注释,读懂示例代码,自行模仿设计Server端和Client端,要求能运用SOCK_STREAM,实现使用端口8888的Server端和Client端,能够进行最简单的聊天功能,你一句我一句交互即可。
参考与资料扩展:
•代码中注释
•谷歌搜索
•MSDN

客户端代码:

#include "stdafx.h"#include "winsock2.h"#pragma comment(lib,"ws2_32.lib")#define BUFFSIZE    80int _tmain(int argc, _TCHAR* argv[]){    WORD        wVersionRequested;    WSADATA        wsaData;    SOCKET        sockfd;        SOCKADDR_IN servAddr;    wVersionRequested = MAKEWORD(2,2);            if (WSAStartup(wVersionRequested,&wsaData) != 0)    {        printf("Winsock init fail!\n");        return (-1);            }    sockfd = socket(AF_INET,SOCK_STREAM,0);    if (sockfd == INVALID_SOCKET) {        printf("Create socket fail!\n");        WSACleanup();        return (-1);    }            servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");    servAddr.sin_family = AF_INET;    servAddr.sin_port = htons(6000);        // 向服务器发送连接请求    if(connect(sockfd, (SOCKADDR*)&servAddr, sizeof(SOCKADDR)) == SOCKET_ERROR)     {        printf("Connect fail!\n");        return (-1);    } else         printf("Connect success!\n");    // 和服务器进行通信            char    buffSend[BUFFSIZE], buffRecv[BUFFSIZE];    int        count;    while (true)    {        printf("Send: ");        gets(buffSend);        if((send(sockfd, buffSend, strlen(buffSend), 0)) == SOCKET_ERROR)        {            printf("Send fail!\n");            return (-1);        }        if((count = recv(sockfd, buffRecv, BUFFSIZE, 0)) == SOCKET_ERROR)        {            printf("Recv fail!\n");            return (-1);        }        buffRecv[count] = '\0';        printf("Received :[%d bytes] %s  \n",  count, buffRecv);        if(!strcmp(buffRecv, "88"))             break;            }    if (closesocket(sockfd) == SOCKET_ERROR)    {            printf("Close fail!\n");            return (-1);    }    WSACleanup();        getchar();    return 0;}

服务器代码:

#include "stdafx.h"#include "winsock2.h"#pragma comment(lib,"ws2_32.lib")    // 连接socket所需的库文件#define BUFFSIZE    80int _tmain(int argc, _TCHAR* argv[]){    WORD        wVersionRequested;        // 用于指定Winsock版本号(如早期的windsock1.1,现在的winsock2.x)    WSADATA        wsaData;                // 用于返回winsock版本信息    SOCKET        sockfd, connfd;            // 套接字描述符、连接描述符    SOCKADDR_IN servAddr, cliAddr;        // SOCKADDR_IN是一种通用Socket地址结构    // 使用MAKEWORD宏可以给一个WORD类型赋值。此处表示主版本号为2,副版本号为2,即winsock2.2    wVersionRequested = MAKEWORD(2,2);        /////// 1. 加载Winsock的动态链接库,WSAStartup()        // WSAStartup()会根据指定Winsock版本搜索相应的动态链接库并进行绑定,成功则返回0    if (WSAStartup(wVersionRequested,&wsaData) != 0)    {        printf("Winsock init fail!\n");        return (-1);            }///////// 2. 创建一个可用的套接字,socket()    // 第一个参数为int af,用来指定使用的地址族,TCP/IP协议为AF_INET(比较常用)、Xerox协议为AF_NS、UNIX协议为AF_UNIX等    // 第二个参数为int type,用来指定创建的套接字类型,有SOCK_DGRAM、SOCK_STREAM、SOCK_RAW等    // 第三个参数为int protocol,用来指定使用的具体协议,根据地址格式和Socket类型自动选择,通常设为0    sockfd = socket(AF_INET, SOCK_STREAM, 0);    // 返回值为套接字描述符SOCKET,若失败则返回INVALID_SOCKET    if (sockfd == INVALID_SOCKET) {        printf("Create socket fail!\n");        WSACleanup();    // 释放资源        return (-1);    }///////// 3. 将套接字与本地地址相互绑定,bind()        // 将地址转为所需格式     // sin_family指定使用的地址族    servAddr.sin_family = AF_INET;    // sin_addr指定使用的IP,设为INADDR_ANY表示分配给本机的所有IP地址    // htonl()将主机的无符号长整形数转换成网络字节顺序        servAddr.sin_addr.s_addr = htonl(INADDR_ANY);    // sin_port指定使用的端口号    // htos()将一个无符号短整型数值转换为网络字节序    servAddr.sin_port = htons(6000);    // 第一个参数为欲绑定套接字描述符,第二个参数为欲绑定本地地址,第三个参数为本地地址结构的长度    if (bind(sockfd, (SOCKADDR*)&servAddr, sizeof(SOCKADDR)) == SOCKET_ERROR)     {        printf("Bind fail!\n");        return (-1);    }  else        printf("Server running:\n");        // 4. 将套接字设置为监听模式等待连接请求,listen()        // 第一个参数为套接字描述符,第二个参数为客户连接请求队列的最大长度    if(listen(sockfd, 5) == SOCKET_ERROR)    {        printf("Listen fail!\n");        return (-1);    }        // 5. 设置等待连接请求,处理请求accept(), recv(), send()    int len = sizeof(SOCKADDR);    char buff[BUFFSIZE];    int    count;    while (true)    {            // 阻塞式等待请求,接受连接        if((connfd = accept(sockfd, (SOCKADDR*)&cliAddr, &len)) == SOCKET_ERROR)        {            printf("Accept fail!\n");            return (-1);        }        printf("A client connect!\n");        while(true) {            // 接收数据            if((count = recv(connfd, buff, BUFFSIZE, 0)) == SOCKET_ERROR)             {                printf("Recv fail!\n");                break;            }            buff[count] = '\0';            printf("Receive:[%d bytes] %s\n", count, buff);                            // 返回接收到的数据            if((send(connfd, buff, strlen(buff), 0)) == SOCKET_ERROR)            {                printf("Send fail!\n");                break;            }            if(!strcmp(buff, "88"))                 break;        }        // 关闭套接字        if (closesocket(connfd) == SOCKET_ERROR)        {            printf("Close fail!\n");            return (-1);        }    }    if (closesocket(sockfd) == SOCKET_ERROR)    {        printf("Close fail!\n");        return (-1);    }    // 卸载Winsock的动态链接库    if(WSACleanup() == SOCKET_ERROR)    {        printf("Clean fail!\n");        return (-1);    }    return 0;}

 

原创粉丝点击