C++Socket接口编程

  1. 实验目的

1. 学习网络进程间通信

2. 深刻理解Client/Server模型

3. 熟练掌握Socket编程接口(API)

3.1 基于UDP协议通信编程(单向,双向,视频文件传输)

3.2 基于TCP协议通信编程(单向,双向,视频文件传输)

2、实验要求

UDP : 

n 单向通信:客户端将从键盘输入任意字符串发送给服 务器,服务器接收到后将该字符串在屏幕上打印,并 将客户端IP地址和PORT打印;

n 双向通信:( 1)客户端将从键盘输入任意字符串发送 给服务器,服务器接收到后将该字符串在屏幕上打印, 并将客户端IP地址和PORT打印;( 2)服务器将客户 端发送来字符串的服务器发送给客户端,客户端打印 字符串和服务器IP地址和PORT;

 n 传输多媒体文件:客户端将一个视频文件发送给服务 器,在服务器上是否能播放;在发送过程中将“网络 接口 -停止”( 3 到 6秒),检测可否正常传输文件。

TCP:

问题1:基于TCP协议通信中,客户端何时知道通信五元组。

SOCKET socket( int af, int type, int protocol );

int connect(SOCKET socketid, const struct sockaddr FAR *seradd, int seraddlen )

问题2:基于TCP协议通信中,客户端何时知道通信五元组。

SOCKET socket( int af, int type, int protocol );

int bind( SOCKET socketid, const struct sockaddr FAR * seradd, int seraddlen )

LISTEN();

SOCKET accept( SOCKET s, struct sockaddr FAR * cliaddr,int FAR * cliaddrlen )

结论:服务器只要调用了accept,才知道五元组;连接建立好以后,CLIENT与SERVER谁先发送TCP数据段都可以。

、相关技术及知识

1. 网络间进程通信

 

2. Client/Server模式

网络中进程间通信模式:客户/ 服务(C/S:Client/Server)模式。

客户向服务器主动发出服务请求,服务器等待接收服务请求,并根据自身的资源状态进行应答与服务。

TCP协议:客户进程首先主动向服务器进程发送连接请求,通过三次握手,建立连接,实际上是获得五元组(连接表);通信时任意一方可以向对方发送数据;通信结束后,任一方可通过四次握手释放连接。

UDP协议:客户进程必须首先主动向服务器进程发送服务请求(数据),这时服务器才得到通信五元组信息;此后,服务器才可以向客户进程发送应答。

 

 

 

3. Socket编程接口

  1. 为了便于网络进程间使用TCP/UDP进行通信,传输层向应用层提供了一套编程接口—套接字(Socket)编程接口。
  2. 套接字编程接口包括以下主要API:
    1. 创建socket:socket( )
    2. 绑定本地地址:bind( ) – 主要用于服务器端
    3. 建立socket连接:connect( )
    4. 接收连接请求:listen( ) 、accept( )
    5. 发送数据:send( ) , sendto( )
    6. 接收数据:recv( ) , recvfrom( )

5、程序代码

代码及可执行程序见附件.

UDP:

2 双向通信:1_2

// udp_client.cpp

#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <iostream>
#include <string>
#include <stdio.h>

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

int main()
{

    int iResult = 0;

    WSADATA wsaData;

    SOCKET SendSocket;
    struct sockaddr_in RecvAddr;
    int RecvAddrSize = sizeof (RecvAddr);

    unsigned short Port = 6666;

    struct sockaddr_in SendAddr;
    int SendAddrSize = sizeof (SendAddr);

    //-----------------------------------------------
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        wprintf(L"WSAStartup failed with error %d\n", iResult);
        return 1;
    }
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (SendSocket == INVALID_SOCKET) {
        wprintf(L"socket failed with error %d\n", WSAGetLastError());
        return 1;
    }
    //-----------------------------------------------
    // Bind the socket to any address and the specified port.
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    wprintf(L"Sending datagrams...\n");

    std::string str;
    std::cout << "Please input your message: ";
    std::cin >> str;
    iResult = sendto(SendSocket, str.c_str(), str.length(), 0, (SOCKADDR *) &RecvAddr, RecvAddrSize);
    if (iResult == SOCKET_ERROR) {
        wprintf(L"sen failed with error %d\n", WSAGetLastError());
    }
    wprintf(L"Finished sending.\n");

    char RecvBuf[1024] = {0};    // 接收数据的buffer
    int BufLen = 1024;           // buffer 长度
    iResult = recvfrom(SendSocket,
                       RecvBuf, BufLen, 0, (SOCKADDR *)&SendAddr, &SendAddrSize);
    wprintf(L"Finished receiving from %s:%u. Closing socket.\n", inet_ntoa(SendAddr.sin_addr), SendAddr.sin_port);
    printf("Message: %s\n", RecvBuf);
    //-----------------------------------------------
    // Close the socket when finished receiving datagrams
    iResult = closesocket(SendSocket);
    if (iResult == SOCKET_ERROR) {
        wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
        return 1;
    }

    //-----------------------------------------------
    // Clean up and exit.
    wprintf(L"Exiting.\n");
    WSACleanup();
    return 0;
}
//udp_server.cpp
//#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <WS2tcpip.h>
#include <Ws2tcpip.h>
#include <stdio.h>

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

using namespace std;
int main()
{

    int iResult = 0;

    WSADATA wsaData;

    SOCKET RecvSocket;           //服务端用于接收客户端书局的套接字
    struct sockaddr_in RecvAddr; //服务端监听的地址
    unsigned short Port = 6666;  //服务端监听的端口
    //-----------------------------------------------
    // Bind the socket to any address and the specified port.
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = inet_addr("0.0.0.0");

    //-----------------------------------------------
    // 初始化 Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR)
    {
        wprintf(L"WSAStartup failed with error %d\n", iResult);
        return 1;
    }
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    // 创建服务端接收数据的套接字
    RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (RecvSocket == INVALID_SOCKET)
    {
        wprintf(L"socket failed with error %d\n", WSAGetLastError());
        return 1;
    }

    //绑定0.0.0.0:6666
    iResult = bind(RecvSocket, (SOCKADDR *)&RecvAddr, sizeof(RecvAddr));
    if (iResult != 0)
    {
        wprintf(L"bind failed with error %d\n", WSAGetLastError());
        return 1;
    }


    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    wprintf(L"Receiving datagrams...\n");
    char RecvBuf[1024] = {0};    // 接收数据的buffer
    int BufLen = 1024;           // buffer 长度
    struct sockaddr_in SendAddr; // recvfrom的传入参数, recvfrom成功后为发送者的地址
    int SendAddrSize = sizeof(SendAddr);
    iResult = recvfrom(RecvSocket,
                       RecvBuf, BufLen, 0, (SOCKADDR *)&SendAddr, &SendAddrSize);
    if (iResult == SOCKET_ERROR)
    {
        wprintf(L"recvfrom failed with error %d\n", WSAGetLastError());
    }

    //-----------------------------------------------
    wprintf(L"Finished receiving from %s:%u. Sending back.\n", inet_ntoa(SendAddr.sin_addr), SendAddr.sin_port);
    printf("Message: %s\n", RecvBuf);

    // 将接收的数据包发回去
    iResult = sendto(RecvSocket, RecvBuf, strlen(RecvBuf), 0, (SOCKADDR *)&SendAddr, SendAddrSize);

    wprintf(L"Finished send to %s:%u. Closing socket.\n", inet_ntoa(SendAddr.sin_addr), SendAddr.sin_port);
    
    //
    iResult = closesocket(RecvSocket);
    if (iResult == SOCKET_ERROR)
    {
        wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
        return 1;
    }

    //-----------------------------------------------
    // Clean up and exit.
    wprintf(L"Exiting.\n");
    WSACleanup();
    return 0;
}

3 文件传输:1_3 

//udp_client.cpp
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <iostream>
#include <string>
#include <stdio.h>
#include <cstring>
#include <fstream>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
using namespace std;

int main()
{

    int iResult = 0;

    WSADATA wsaData;

    SOCKET SendSocket;
    struct sockaddr_in RecvAddr;
    int RecvAddrSize = sizeof(RecvAddr);

    unsigned short Port = 6666;

    struct sockaddr_in SendAddr;
    int SendAddrSize = sizeof(SendAddr);

    //-----------------------------------------------
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR)
    {
        wprintf(L"WSAStartup failed with error %d\n", iResult);
        return 1;
    }
    //-----------------------------------------------
    // Create a send socket to receive datagrams
    SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (SendSocket == INVALID_SOCKET)
    {
        wprintf(L"socket failed with error %d\n", WSAGetLastError());
        return 1;
    }
    //-----------------------------------------------
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    wprintf(L"Sending datagrams...\n");

    // std::string str;
    // std::cout << "Please input your message: ";
    // std::cin >> str;
    // iResult = sendto(SendSocket, str.c_str(), str.length(), 0, (SOCKADDR *)&RecvAddr, RecvAddrSize);
    int haveSend = 0;
    const int bufferSize = 1024;
    char buffer[bufferSize] = {0};
    int readLen = 0;
    string srcFileName = "1111.avi";
    ifstream srcFile;
    srcFile.open(srcFileName.c_str(), ios::binary);
    if (!srcFile)
    {
        return 1;
    }
    int ir;
    while (!srcFile.eof())
    {
        srcFile.read(buffer, bufferSize);
        readLen = srcFile.gcount();
        // cout <<"readlen:" <<readLen<<endl;
        iResult=sendto(SendSocket, buffer, readLen, 0,(SOCKADDR *)&RecvAddr, RecvAddrSize);
        haveSend += readLen;
        cout <<"send accesss! Havesend:" << haveSend<<endl;
        Sleep(0.01);

    }
    srcFile.close();
    cout << "send: " << haveSend << "B" << endl;
    if (iResult == SOCKET_ERROR)
    {
        wprintf(L"sen failed with error %d\n", WSAGetLastError());
    }
    wprintf(L"Finished sending.\n");
    // char RecvBuf[1024] = {0}; // 接收数据的buffer
    // int BufLen = 1024;        // buffer 长度
    // iResult = recvfrom(SendSocket,
    //                    RecvBuf, BufLen, 0, (SOCKADDR *)&SendAddr, &SendAddrSize);
    // wprintf(L"Finished receiving from %s:%u. Closing socket.\n", inet_ntoa(SendAddr.sin_addr), SendAddr.sin_port);
    // printf("Message: %s\n", RecvBuf);
    //-----------------------------------------------
    // Close the socket when finished receiving datagrams
    iResult = closesocket(SendSocket);
    if (iResult == SOCKET_ERROR)
    {
        wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
        return 1;
    }
    //-----------------------------------------------
    // Clean up and exit.
    wprintf(L"Exiting.\n");
    WSACleanup();
    return 0;
}
//udp_server.cpp

#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <WS2tcpip.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

int main()
{

    int iResult = 0;

    WSADATA wsaData;

    SOCKET RecvSocket;           //服务端用于接收客户端书局的套接字
    struct sockaddr_in RecvAddr; //服务端监听的地址
    unsigned short Port = 6666;  //服务端监听的端口
    //-----------------------------------------------
    // Bind the socket to any address and the specified port.
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = inet_addr("0.0.0.0");

    //-----------------------------------------------
    // 初始化 Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR)
    {
        wprintf(L"WSAStartup failed with error %d\n", iResult);
        return 1;
    }
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    // 创建服务端接收数据的套接字
    RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (RecvSocket == INVALID_SOCKET)
    {
        wprintf(L"socket failed with error %d\n", WSAGetLastError());
        return 1;
    }

    //绑定0.0.0.0:6666
    iResult = bind(RecvSocket, (SOCKADDR *)&RecvAddr, sizeof(RecvAddr));
    if (iResult != 0)
    {
        wprintf(L"bind failed with error %d\n", WSAGetLastError());
        return 1;
    }

    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    wprintf(L"Receiving datagrams...\n");
    // char RecvBuf[1024] = {0};    // 接收数据的buffer
    // int BufLen = 1024;           // buffer 长度
    struct sockaddr_in SendAddr; // recvfrom的传入参数, recvfrom成功后为发送者的地址
    int SendAddrSize = sizeof(SendAddr);
    // iResult = recvfrom(RecvSocket,
    //                    RecvBuf, BufLen, 0, (SOCKADDR *)&SendAddr, &SendAddrSize);
    // if (iResult == SOCKET_ERROR)
    // {
    //     wprintf(L"recvfrom failed with error %d\n", WSAGetLastError());
    // }
    // //-----------------------------------------------
    // wprintf(L"Finished receiving from %s:%u. Sending back.\n", inet_ntoa(SendAddr.sin_addr), SendAddr.sin_port);
    // printf("Message: %s\n", RecvBuf);

    // // 将接收的数据包发回去
    // iResult = sendto(RecvSocket, RecvBuf, strlen(RecvBuf), 0, (SOCKADDR *)&SendAddr, SendAddrSize);

    // wprintf(L"Finished send to %s:%u. Closing socket.\n", inet_ntoa(SendAddr.sin_addr), SendAddr.sin_port);
    cout << "start recv!" << endl;
    int bufferSize = 1024;
    char buffer[1024] = {0};
    int readLen = 0;
    string desFileName = "received.avi";
    ofstream desFile;
    desFile.open(desFileName.c_str(), ios::binary);
    if (!desFile)
    {
        cout << "open failed!" << endl;
        return 1;
    }
    int sumlen = 0;
    do
    {
        readLen = recvfrom(RecvSocket, buffer, bufferSize, 0, (SOCKADDR *)&SendAddr, &SendAddrSize);
        if (readLen == SOCKET_ERROR)
        {
            cout << "receive failed!" << endl;
            break;
        }
        else
        {
            desFile.write(buffer, bufferSize);
            sumlen += bufferSize;
            cout << "file write success!" << sumlen << endl;
            if (sumlen > 3838464)
                break;
        }

    } while (true);
    desFile.close();
    cout << " recv finish!" << endl; //
    iResult = closesocket(RecvSocket);
    if (iResult == SOCKET_ERROR)
    {
        wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
        return 1;
    }

    //-----------------------------------------------
    // Clean up and exit.
    wprintf(L"Exiting.\n");
    WSACleanup();
    return 0;
}

TCP:

2 双向通信:2_2

//client.cpp
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <iostream>
#include <string>
#include <stdio.h>
#include <iostream>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
int main()
{

    int iResult = 0;

    WSADATA wsaData;

    SOCKET SendSocket;
    struct sockaddr_in RecvAddr;
    int RecvAddrSize = sizeof(RecvAddr);

    unsigned short Port = 6666;

    struct sockaddr_in SendAddr;
    int SendAddrSize = sizeof(SendAddr);

    //-----------------------------------------------
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR)
    {
        wprintf(L"WSAStartup failed with error %d\n", iResult);
        return 1;
    }
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    SendSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (SendSocket == INVALID_SOCKET)
    {
        wprintf(L"socket failed with error %d\n", WSAGetLastError());
        return 1;
    }
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (connect(SendSocket, (SOCKADDR *)&RecvAddr, RecvAddrSize) == INVALID_SOCKET)
    {
        cout << "connect() failed: " << WSAGetLastError() << endl;
        return 1;
    }
    //-----------------------------------------------
    std::string str;
    std::cout << "Please input your message: ";
    std::cin >> str;
    iResult = send(SendSocket, str.c_str(), str.length(), 0);
    if (iResult == SOCKET_ERROR)
    {
        wprintf(L"sen failed with error %d\n", WSAGetLastError());
    }
    wprintf(L"Finished sending.\n");
    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    char RecvBuf[1024] = {0}; // 接收数据的buffer
    int BufLen = 1024;        // buffer 长度
    iResult = recv(SendSocket, RecvBuf, BufLen, 0);
    if (iResult == SOCKET_ERROR)
    {
        cout << "rcv() failed:" << WSAGetLastError() << endl;
        return 1;
    }
    wprintf(L"Finished receiving from %s:%u. Closing socket.\n", inet_ntoa(RecvAddr.sin_addr), RecvAddr.sin_port);
    printf("Message: %s\n", RecvBuf);
    //-----------------------------------------------
    // Close the socket when finished receiving datagrams
    iResult = closesocket(SendSocket);
    if (iResult == SOCKET_ERROR)
    {
        wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
        return 1;
    }

    //-----------------------------------------------
    // Clean up and exit.
    wprintf(L"Exiting.\n");
    WSACleanup();
    return 0;
}
//server.cpp
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <WS2tcpip.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <iostream>
using namespace std;
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

int main()
{

  int iResult = 0;

  WSADATA wsaData;

  SOCKET RecvSocket;           //服务端用于接收客户端书局的套接字
  struct sockaddr_in RecvAddr; //服务端监听的地址
  unsigned short Port = 6666;  //服务端监听的端口
  //-----------------------------------------------
  // Bind the socket to any address and the specified port.
  RecvAddr.sin_family = AF_INET;
  RecvAddr.sin_port = htons(Port);
  RecvAddr.sin_addr.s_addr = inet_addr("0.0.0.0");

  //-----------------------------------------------
  // 初始化 Winsock
  iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
  if (iResult != NO_ERROR)
  {
    wprintf(L"WSAStartup failed with error %d\n", iResult);
    return 1;
  }
  //-----------------------------------------------
  // Create a receiver socket to receive datagrams
  // 创建服务端接收数据的套接字
  RecvSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (RecvSocket == INVALID_SOCKET)
  {
    wprintf(L"socket failed with error %d\n", WSAGetLastError());
    return 1;
  }

  //绑定0.0.0.0:6666
  iResult = bind(RecvSocket, (SOCKADDR *)&RecvAddr, sizeof(RecvAddr));
  if (iResult != 0)
  {
    wprintf(L"bind failed with error %d\n", WSAGetLastError());
    return 1;
  }
  iResult = listen(RecvSocket, 5);
  if (iResult == SOCKET_ERROR)
  {
    cout << "listen() failed:" << WSAGetLastError() << endl;
    return 1;
  }
  wprintf(L"Receiving datagrams...\n");
  char RecvBuf[1024] = {0};    // 接收数据的buffer
  int BufLen = 1024;           // buffer 长度
  struct sockaddr_in SendAddr; // recvfrom的传入参数, recvfrom成功后为发送者的地址
  int SendAddrSize = sizeof(SendAddr);

  SOCKET newSocket = accept(RecvSocket, (SOCKADDR *)&SendAddr, &SendAddrSize);
  if (newSocket == INVALID_SOCKET)
  {
    cout << "accept() failed:" << WSAGetLastError() << endl; //
    return 1;
  }
  iResult = recv(newSocket, RecvBuf, BufLen, 0);
  if (iResult == SOCKET_ERROR)
  {
    cout << "rcv() failed:" << WSAGetLastError() << endl;
    return 1;
  }
  if (iResult == 0)
  {
    cout << "no receive message!" << endl;
  }
  else
  {
    cout << "received success, message :" << RecvBuf << endl;
    cout << "ip:port:" << inet_ntoa(SendAddr.sin_addr) << SendAddr.sin_port << endl;
  }
  iResult = send(newSocket, RecvBuf, BufLen, 0);
  if (iResult == SOCKET_ERROR)
  {
    cout << "send() failed:" << WSAGetLastError() << endl;
    return 1;
  }
  if (iResult == 0)
  {
    cout << "no send message!" << endl;
  }
  else
  {
    cout << "send success, message: " << RecvBuf << endl;
  }
  //-----------------------------------------------
  // wprintf(L"Finished receiving from %s:%u. Sending back.\n", inet_ntoa(SendAddr.sin_addr), SendAddr.sin_port);
  // printf("Message: %s\n", RecvBuf);

  // // 将接收的数据包发回去
  // iResult = sendto(RecvSocket, RecvBuf, strlen(RecvBuf), 0, (SOCKADDR *)&SendAddr, SendAddrSize);

  // wprintf(L"Finished send to %s:%u. Closing socket.\n", inet_ntoa(SendAddr.sin_addr), SendAddr.sin_port);

  // //
  iResult = closesocket(RecvSocket);
  if (iResult == SOCKET_ERROR)
  {
    wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
    return 1;
  }
  WSACleanup();
  closesocket(newSocket);
  wprintf(L"Exiting.\n");
  return 0;
}

3 文件传输:2_3 

//client.cpp

#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <iostream>
#include <string>
#include <stdio.h>
#include <iostream>
#include <fstream>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
int main()
{

	int iResult = 0;

	WSADATA wsaData;

	SOCKET SendSocket;
	struct sockaddr_in RecvAddr;
	int RecvAddrSize = sizeof(RecvAddr);

	unsigned short Port = 6666;

	struct sockaddr_in SendAddr;
	int SendAddrSize = sizeof(SendAddr);

	//-----------------------------------------------
	// Initialize Winsock
	iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != NO_ERROR)
	{
		wprintf(L"WSAStartup failed with error %d\n", iResult);
		return 1;
	}
	//-----------------------------------------------
	// Create a receiver socket to receive datagrams
	SendSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (SendSocket == INVALID_SOCKET)
	{
		wprintf(L"socket failed with error %d\n", WSAGetLastError());
		return 1;
	}
	RecvAddr.sin_family = AF_INET;
	RecvAddr.sin_port = htons(Port);
	RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	if (connect(SendSocket, (SOCKADDR *)&RecvAddr, RecvAddrSize) == INVALID_SOCKET)
	{
		cout << "connect() failed: " << WSAGetLastError() << endl;
		return 1;
	}
	//-----------------------------------------------
	int haveSend = 0;
	const int bufferSize = 1024;
	char buffer[bufferSize] = {0};
	int readLen = 0;
	string srcFileName = "1111.avi";
	ifstream srcFile;
	srcFile.open(srcFileName.c_str(), ios::binary);
	if (!srcFile)
	{
		return 1;
	}
	while (!srcFile.eof())
	{
		srcFile.read(buffer, bufferSize);
		readLen = srcFile.gcount();
		send(SendSocket, buffer, readLen, 0);
		haveSend += readLen;
		cout << "send accesss! Havesend:" << haveSend << endl;
		Sleep(0.01);
	}
	srcFile.close();
	cout << "send: " << haveSend << "B" << endl;

	//
	// iResult = send(SendSocket, str.c_str(), str.length(), 0);
	// if (iResult == SOCKET_ERROR)
	// {
	// 	wprintf(L"sen failed with error %d\n", WSAGetLastError());
	// }
	// wprintf(L"Finished sending.\n");
	// //-----------------------------------------------
	// // Call the recvfrom function to receive datagrams
	// // on the bound socket.
	// char RecvBuf[1024] = {0}; // 接收数据的buffer
	// int BufLen = 1024;		  // buffer 长度
	// iResult = recv(SendSocket, RecvBuf, BufLen, 0);
	// if (iResult == SOCKET_ERROR)
	// {
	// 	cout << "rcv() failed:" << WSAGetLastError() << endl;
	// 	return 1;
	// }
	// wprintf(L"Finished receiving from %s:%u. Closing socket.\n", inet_ntoa(RecvAddr.sin_addr), RecvAddr.sin_port);
	// printf("Message: %s\n", RecvBuf);
	//-----------------------------------------------
	// Close the socket when finished receiving datagrams
	iResult = closesocket(SendSocket);
	if (iResult == SOCKET_ERROR)
	{
		wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
		return 1;
	}

	//-----------------------------------------------
	// Clean up and exit.
	wprintf(L"Exiting.\n");
	WSACleanup();
	return 0;
}
//server.cpp
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <WS2tcpip.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

int main()
{

  int iResult = 0;

  WSADATA wsaData;

  SOCKET RecvSocket;           //服务端用于接收客户端书局的套接字
  struct sockaddr_in RecvAddr; //服务端监听的地址
  unsigned short Port = 6666;  //服务端监听的端口
  //-----------------------------------------------
  // Bind the socket to any address and the specified port.
  RecvAddr.sin_family = AF_INET;
  RecvAddr.sin_port = htons(Port);
  RecvAddr.sin_addr.s_addr = inet_addr("0.0.0.0");

  //-----------------------------------------------
  // 初始化 Winsock
  iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
  if (iResult != NO_ERROR)
  {
    wprintf(L"WSAStartup failed with error %d\n", iResult);
    return 1;
  }
  //-----------------------------------------------
  // Create a receiver socket to receive datagrams
  // 创建服务端接收数据的套接字
  RecvSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (RecvSocket == INVALID_SOCKET)
  {
    wprintf(L"socket failed with error %d\n", WSAGetLastError());
    return 1;
  }

  //绑定0.0.0.0:6666
  iResult = bind(RecvSocket, (SOCKADDR *)&RecvAddr, sizeof(RecvAddr));
  if (iResult != 0)
  {
    wprintf(L"bind failed with error %d\n", WSAGetLastError());
    return 1;
  }
  iResult = listen(RecvSocket, 5);
  if (iResult == SOCKET_ERROR)
  {
    cout << "listen() failed:" << WSAGetLastError() << endl;
    return 1;
  }
  wprintf(L"Receiving datagrams...\n");
  char RecvBuf[1024] = {0};    // 接收数据的buffer
  int BufLen = 1024;           // buffer 长度
  struct sockaddr_in SendAddr; // recvfrom的传入参数, recvfrom成功后为发送者的地址
  int SendAddrSize = sizeof(SendAddr);

  SOCKET newSocket = accept(RecvSocket, (SOCKADDR *)&SendAddr, &SendAddrSize);
  if (newSocket == INVALID_SOCKET)
  {
    cout << "accept() failed:" << WSAGetLastError() << endl; //
    return 1;
  }
  cout << "start recv!" << endl;
  const int bufferSize = 1024;
  char buffer[bufferSize] = {0};
  int readLen = 0;
  string desFileName = "receive.avi";
  ofstream desFile;
  desFile.open(desFileName.c_str(), ios::binary);
  if (!desFile)
  {
    return 1;
  }
  int sumlen = 0;
  do
  {
    readLen = recv(newSocket, buffer, bufferSize, 0);
    if (readLen == 0)
    {
      cout << "receive failed!" << endl;
      break;
    }
    else
    {
      desFile.write(buffer, readLen);
      sumlen += bufferSize;
      cout << "file write success!" << sumlen << endl;
      if (sumlen > 3838464)
        break;
    }
  } while (true);
  desFile.close();
  //

  // iResult = recv(newSocket, RecvBuf, BufLen, 0);
  // if (iResult == SOCKET_ERROR)
  // {
  //   cout << "rcv() failed:" << WSAGetLastError() << endl;
  //   return 1;
  // }
  // if (iResult == 0)
  // {
  //   cout << "no receive message!" << endl;
  // }
  // else
  // {
  //   cout << "received success, message :" << RecvBuf << endl;
  //   cout << "ip:port:" << inet_ntoa(SendAddr.sin_addr) << SendAddr.sin_port << endl;
  // }
  // iResult = send(newSocket, RecvBuf, BufLen, 0);
  // if (iResult == SOCKET_ERROR)
  // {
  //   cout << "send() failed:" << WSAGetLastError() << endl;
  //   return 1;
  // }
  // if (iResult == 0)
  // {
  //   cout << "no send message!" << endl;
  // }
  // else
  // {
  //   cout << "send success, message: " << RecvBuf << endl;
  // }
  //-----------------------------------------------
  // wprintf(L"Finished receiving from %s:%u. Sending back.\n", inet_ntoa(SendAddr.sin_addr), SendAddr.sin_port);
  // printf("Message: %s\n", RecvBuf);

  // // 将接收的数据包发回去
  // iResult = sendto(RecvSocket, RecvBuf, strlen(RecvBuf), 0, (SOCKADDR *)&SendAddr, SendAddrSize);

  // wprintf(L"Finished send to %s:%u. Closing socket.\n", inet_ntoa(SendAddr.sin_addr), SendAddr.sin_port);

  // //
  iResult = closesocket(RecvSocket);
  if (iResult == SOCKET_ERROR)
  {
    wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
    return 1;
  }
  WSACleanup();
  closesocket(newSocket);
  wprintf(L"Exiting.\n");
  return 0;
}

6、运行结果与分析

UDP:

2 双向通信:1_2

3 文件传输:1_3 

TCP:

2 双向通信:2_2

3 文件传输:2_3 

 

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验内容 根据自定义的协议规范,使用 Socket 编程接口编写基本的网络应用软件。 掌握 C 语言形式的 Socket 编程接口用法,能够正确发送和接收网络数据包。 开发一个客户端,实现人机交互界面和与服务器的通信。 开发一个服务端,实现并发处理多个客户端的请求。 程序界面不做要求,使用命令行或最简单的窗体即可。 功能要求如下: 运输层协议采用 TCP 客户端采用交互菜单形式,用户可以选择以下功能: a) 连接:请求连接到指定地址和端口的服务端。 b) 断开连接:断开与服务端的连接。 c)获取时间: 请求服务端给出当前时间。 d)获取名字:请求服务端给出其机器的名称。 e)活动连接列表:请求服务端给出当前连接的所有客户端信息(编号、IP 地址、端口等) f)发消息:请求服务端把消息转发给对应编号的客户端,该客户端收到后显示在屏幕上 g) 退出:断开连接并退出客户端程序 3.服务端接收到客户端请求后,根据客户端传过来的指令完成特定任务: a)向客户端传送服务端所在机器的当前时间。 b)向客户端传送服务端所在机器的名称。 c)向客户端传送当前连接的所有客户端信息。 d)将某客户端发送过来的内容转发给指定编号的其他客户端。 e)采用异步多线程编程模式,正确处理多个客户端同时连接,同时发送消息的情况。 根据上述功能要求,设计一个客户端和服务端之间的应用通信协议。 本实验涉及到网络数据包发送部分不能使用任何的 Socket 封装类,只能使用最底层的 C 语言形式的 Socket API。 本实验可组成小组,服务端和客户端可由不同人来完成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值