实验三 面向非连接的基础Socket编程
一、 实验目的
1.了解面向非连接的Socket通信流程。
2.掌握使用WinSock函数编写面向非连接的网络应用程序的方法。
二、实验内容
利用数据报套接字编程实现网络通信程序。要求如下:
1.发送端从控制台读取信息并发送,接收端接收信息后打印信息然后回送收到的信息。信息的发送和接收可以多次进行。当收到的信息为“exit”时,双方程序退出。
2.启动发送端和接收端程序进行信息收发测试。
三、实验原理
面向非连接就是udp通信
数据报式套接字提供无连接的书籍传输服务。数据包被独立的发送,数据可能丢失或重复。
在无连接服务中,每次数据传输并不需要建立连接,因此每个分组数据包中必须包含完整的目的地址,并且每个数据包都独立的在网络中传输。无连接服务不能保证分组的先后顺序,不能保证数据传输的可靠性。Udp提供无连接的数据报服务。
面向非连接的socket通信流程比较简单,在服务器程序中不需要调用listen()和accept()函数来等待客户端的连接;在客户端程序中也不需要与服务器建立连接,而是直接向服务器发送数据。
四、实验步骤
Server:
1.建立数据报式套接字,返回套接字号s【socket( )】
2.套接字s与本地地址(IP+端口)绑定【bind( )】
3.在套接字ns上读/写数据,直到结束【sendto( )】【recvfrom( )】
4.关闭套接字ns 【closesocket( )】
Client:
1.建立数据报式套接字,返回套接字号s【socket( )】
2.在套接字ns上读/写数据,直到结束【sendto( )】【recvfrom( )】
3.关闭套接字ns 【closesocket( )】
五、实验小结
附:程序源代码
Server:
// Udp_server.cpp: 定义控制台应用程序的入口点。
//
//相关头文件
#include "stdafx.h"
#include <WinSock2.h>
#include <stdio.h>
#include <iostream>
#pragma comment(lib,"WS2_32.lib")
int main()
{
//初始化
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("WSAStartup initialization failed");
return 0;
}
//变量的声明,赋值
SOCKET RecvSocket;
sockaddr_in RecvAddr;
int Port = 8888;
char RecvBuf[1024]; //接收缓冲
char SendBuf[1024]; //发送缓冲
int BufLen = 1024;
sockaddr_in SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
//创建接受数据的socket
RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//绑定ip和端口
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
RecvAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
bind(RecvSocket, (SOCKADDR *)&RecvAddr, sizeof(RecvAddr));
printf("UDP Server start successed,waiting for recieve data...\n");
while (true) {
//接收
int re_number = recvfrom(RecvSocket,
RecvBuf,
BufLen,
0,
(SOCKADDR *)&SenderAddr,
&SenderAddrSize
);
if (re_number > 0) {
printf("Recieved UDP data from client :%s\n", &RecvBuf);
if (strcmp(RecvBuf, "exit") == 0)
{
closesocket(RecvSocket);
return 0;
}
}
//发送
gets_s(SendBuf); //获取键盘输入
//发送函数
int send_number = sendto(RecvSocket,
SendBuf, BufLen,
0,
(SOCKADDR *)&SenderAddr,
sizeof(SenderAddr)
);
printf("server_to_client: %s\n", SendBuf);
if (strcmp(SendBuf, "exit") == 0){
closesocket(RecvSocket);
return 0;
}
}
if (WSACleanup() == SOCKET_ERROR)
printf("WSACleanup failed");
return 0;
}
Client:
// Udp_Client.cpp: 定义控制台应用程序的入口点。
//
//相关头文件
#include "stdafx.h"
#include <WinSock2.h>
#include <stdio.h>
#include <iostream>
#include <Ws2tcpip.h> //第35行函数需要此头文件
using namespace std;
#pragma comment(lib,"WS2_32.lib")
int main()
{
//初始化
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("WSAStartup initialization failed");
return 0;
}
//变量的声明,赋值
SOCKET SendSocket;
sockaddr_in RecvAddr; //服务器端的地址
int Port = 8888;
char SendBuf[1024];
char RecvBuf[1024];
int BufLen = 1024;
//创建soclket
SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//设置服务器地址
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
//RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //vs2017不支持此写法
InetPton(AF_INET, _T("127.0.0.1"), &RecvAddr.sin_addr.s_addr);
int RecvAddrSize = sizeof(RecvAddr);
//向服务器发送数据
printf("UDP Client start successed,waiting for sent data...\n");
while (true) {
//scanf_s("%s",SendBuf); //如果使用这个函数,则会向客户端发送死循环的“烫”,原因是没有结束符,空字符串打印出来就是乱码!
//发送
gets_s(SendBuf);
int st = sendto(SendSocket,
SendBuf,
BufLen,
0,
(SOCKADDR *)&RecvAddr,
sizeof(RecvAddr)
);
if (strcmp(SendBuf, "exit") == 0) {
closesocket(SendSocket);
return 0;
}
//接受
int recv_number = recvfrom(SendSocket, RecvBuf, BufLen, 0, (SOCKADDR *)&RecvAddr, &RecvAddrSize);
printf("From server: %s\n" ,RecvBuf);
if (strcmp(RecvBuf, "exit") == 0) {
closesocket(SendSocket);
return 0;
}
if (st == SOCKET_ERROR) {
printf("Exiting.\n");
closesocket(SendSocket);
WSACleanup();
return -1;
}
}
}