UDP 编程
要求
实验一
- 客户端和服务端交互,客户端发送信息
- 服务端显示信息来源并且将接收到的信息回传给发送方
- 服务端使用多线程实现并发
- 观察在服务端启动或者不启动时,客户端运行情况
实验二
- 客户端向服务端发送文件名
- 客户端想服务端传输文件内容
- 双方关闭套接字
- 注意收发速度对文件的传输结果的影响
分析
实验一
首先服务端启动
和tcp的服务端启动类似,不过不需要listen,
只要创建socket并且绑定端口就行。然后就是recvfrom等待客户端连接
一旦客户端发送数据过来了,就创建新线程,在新线程中创建一个新的socket,绑定一个新的未被占用的端口,然后给客户端返回信息。
//创建一个新的socket
newsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (newsocket == INVALID_SOCKET)
{
cout << "Create Transfer socket failed with error: " << WSAGetLastError() << endl;
return -1;
}
sockaddr_in newaddr;
newaddr.sin_family = AF_INET;
newaddr.sin_addr.s_addr = inet_addr(IP_ADDR);
newaddr.sin_addr.S_un.S_addr = INADDR_ANY;
memset(newaddr.sin_zero, 0x00, 8);
int notfirst = 0;
int newaddr_len = sizeof(newaddr);
//bind socket,一个新的端口
iResult = bind(newsocket, (struct sockaddr *)&newaddr, newaddr_len);
if (iResult != 0)
{
cout << "Bind socket failed: " << WSAGetLastError() << endl;
closesocket(newsocket);
return -1;
}
采用循环交互,只要客户端不发送“End”,双方的通信就不会结束
UDP是无连接的,所以无论在服务端是否开启的情况下,客户端都能进行数据发送,因为客户根本不在乎服务端是否接受。
在服务端没有开启的情况下,客户端不能收到服务端的返回,所以会超时错误。
实验二
整个交互的过程是客户端发送文件名,服务端接受到之后,开一个新线程,创建一个新的套接字,绑定一个新的端口来进行余下的文件传输,通过给客户端返回信息来通知新的端口信息。然后,客户端发送文件长度,然后是文件内容,文件发送和接受都是循环的,直到文件传输完全成功
设置了超时时间,在文件传输过程中,一旦发生问题,服务端接收不到后续信息,超时之后自动退出
//设置超时时间
int nTimeOver = 10000;
setsockopt(TransSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeOver, sizeof(nTimeOver));
- 客户端也设置了超时时间,如果在发送文件结束之后,如果超时时间内没有收到服务端的确认信息就自动退出
int nTimeover = 1000;
setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeover, sizeof(nTimeover));
- 关于传输时间控制,使用的是sleep()函数,在前后两次发送之间调用sleep()来降低传输速度,从而可以使得UDP报文的数据不会因为传输速度太快而淹没。
Sleep(100);
实验结果
实验一
服务端开启的时候
客户端参数设置
可以多次发送数据
可以多次发送数据可以接受多个客户端的同时发送数据
服务端关闭的时候
当服务器被关闭的时候
客户端可以正常发送数据,因为UDP不需要建立连接
但是客户端是不可能接收到服务端的返回信息所以会显示错误代码10060,就是在超时时间内接受不到,停止阻塞。
实验二
短文件传输
- 客户端参数设置
PS:
2.txt大小为94643个字节
- 文件传输
此时文件长度还不是很长,每次发送都能被服务端接收到,而且返回信息也是成功。
长文件传输
- 客户端参数设置
PS:
3.pdf大小为183662个字节
- 文件传输
可以从运行结果看出来,当文件过大的时候,容易有一部分的数据不能被接收,非常容易造成内容的丢失。
此时服务端会等到超时时间到了之后自动停止阻塞
- 修改——控制发送速度
在每次发送,开始下一次发送之前,调用sleep函数来降低发送速度,此时,整个文件都能被服务端正确接受。
思考总结
注意初始化,有时候没有初始化会造成很大的问题
UDP发送端的发送频率如果过快,就会导致信息的淹没,接收方不能接收到完整信息
UDP是不可靠传输,所以需要设置超时时间,不然容易导致程序一直等待
如果UDP发送速度过快,会导致数据的淹没,从而出错。
总的来说,可靠的传输TCP虽然设置稍微复杂,但是稳定程度,可靠程度高很多,编程的时候也不容易出现特别奇怪的问题,不可靠传输UDP,虽然看上去简单一些,但是实际编程中会遇到各种乱七八糟的问题,也更加难以调试,难以发现错误。
代码
实验一
Client
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <WinSock2.h>
#include <iostream>
#pragma comment (lib,"ws2_32.lib")
#define MAX_LEN 100000
using namespace std;
int main(int argc, char * argv[])
{
WSADATA ws;
int iResult;
SOCKET ClientSocket = INVALID_SOCKET;
struct sockaddr_in Server_addr;
int Server_len;
//检查参数个数
if (argc != 3)
{
cout << "Need enter target IP and port !" << endl;
return -1;
}
int PORT = atoi(argv[2]);
//初始化 socket
iResult = WSAStartup(MAKEWORD(2, 2), &ws);
if (iResult != 0)
{
cout << "Initiate failed with error: " << GetLastError() << endl;
WSACleanup();
return -1;
}
//创建 socket
ClientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ClientSocket == INVALID_SOCKET)
{
cout << "Create Client socket failed with error: " << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
Server_addr.sin_family = AF_INET;
Server_addr.sin_addr.s_addr = inet_addr(argv[1]);
Server_addr.sin_port = htons(PORT);
memset(Server_addr.sin_zero, 0x00, 8);
Server_len = sizeof(Server_addr);
char data[MAX_LEN];
cout << "########################################### Interactive Mode ############################################" << endl;
while (TRUE)
{
cout << "Please enter the data to send! Enter \"End\" to close the Interactive mode" << endl;
cin >> data;
cout << endl;
int len = strlen(data);
iResult = sendto(ClientSocket, data, strlen(data), 0, (sockaddr *)&Server_addr, Server_len);
if (iResult != strlen(data) && iResult != MAX_LEN)
{
cout << "Sending failed with error :" << WSAGetLastError() << endl;
cout << "Client exit." << endl;
closesocket(ClientSocket);
WSACleanup();
return -1;
}
else if (iResult == MAX_LEN)
{
cout << "Sending data buffer is already full!\n " << WSAGetLastError() << endl;
}
int Recv_Server_addr_len = 0;
char recvdata[MAX_LEN];
sockaddr_in confire_addr;
int nTimeover = 1000;
setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeover, sizeof(nTimeover));
iResult = recvfrom(ClientSocket, recvdata, MAX_LEN, 0, (sockaddr *)&Server_addr, &Server_len);
if (iResult > 0)
{
recvdata[iResult] = '\0';
cout << "Receive data from Server ( " << inet_ntoa(Server_addr.sin_addr) << " : " << Server_addr.sin_port << " ) successfully!" << endl;
cout << "Receive Data:" << endl;
cout << recvdata << "\n\n" << endl;
if (strcmp(recvdata, "End") == 0)
{
break;
}
}
else if (iResult == 0)
{
cout << "Connection closed!\n" << endl;
}
else
{
cout << "Receive failed with error: " << WSAGetLastError() << endl;
}
}
cout << "Client exit." << endl;
cout << "########################################### Interactive End ############################################\n" << endl;
closesocket(ClientSocket);
WSACleanup();
system("pause");
return 0;
}
Server
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <stdlib.h>
#include <stdint.h>
#include <fstream>
using namespace std;
#pragma comment (lib,"ws2_32.lib")
#define PORT 4000
#define IP_ADDR "0.0.0.0"
#define MAX_LEN 100000
struct inform
{
SOCKET server;
sockaddr_in remote;
int remote_len;
char *data;
};
int newport = 5000;
//多线程函数
DWORD WINAPI ClientThread(LPVOID lpparameter)
{
int iResult = 0;
char data[MAX_LEN];
struct inform para = *(struct inform* ) lpparameter;
SOCKET serSocket = (SOCKET)para.server;
sockaddr_in remotesock = para.remote;
int remotesock_len = para.remote_len;
strcpy(data, para.data);
SOCKET newsocket;
int newsocket_len = sizeof(newsocket);
sockaddr_in interactive;
int interactive_len = sizeof(interactive);
//创建一个新的socket
newsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (newsocket == INVALID_SOCKET)
{
cout << "Create Transfer socket failed with error: " << WSAGetLastError() << endl;
return -1;
}
sockaddr_in newaddr;
newaddr.sin_family = AF_INET;
newaddr.sin_addr.s_addr = inet_addr(IP_ADDR);
newaddr.sin_port = newport++;
newaddr.sin_addr.S_un.S_addr = INADDR_ANY;
memset(newaddr.sin_zero, 0x00, 8);
int notfirst = 0;
int newaddr_len = sizeof(newaddr);
//bind socket,一个新的端口
iResult = bind(newsocket, (struct sockaddr *)&newaddr, newaddr_len);
if (iResult != 0)
{
cout << "Bind socket failed: " << WSAGetLastError() << endl;
closesocket(newsocket);
return -1;
}
cout << "########################################### Interactive Mode ############################################\n" << endl;
while (true)
{
if (notfirst)
{
iResult = recvfrom(newsocket, data, MAX_LEN, 0, (struct sockaddr *)&interactive, &interactive_len);
if (iResult == SOCKET_ERROR || iResult == 0)
{
cout << "Receive data failed with error " << WSAGetLastError() << endl;
closesocket(newsocket);
return -1;
}
data[iResult] = '\0';
}
notfirst = 1;
cout << "Receive from ( " << inet_ntoa(remotesock.sin_addr) << " :" << remotesock.sin_port << " )" << endl;
cout << "Data: " << endl;
cout << data << endl;
cout << "Return Message\n" << endl;
iResult = sendto(newsocket, data, strlen(data), 0, (sockaddr *)&remotesock, remotesock_len);
if (iResult == SOCKET_ERROR || iResult == 0)
{
cout << "Return message failed with error " << WSAGetLastError() << endl;
closesocket(newsocket);
return -1;
}
if (strcmp(data, "End") == 0)
{
break;
}
}
cout << "Return message to " << inet_ntoa(remotesock.sin_addr)<<" finished\n" << endl;
cout << "################################################### Interactive End ###################################################\n\n" << endl;
closesocket(newsocket);
return 0;
}
int main(int argc, char * argv[])
{
WSADATA ws;
SOCKET ServerSocket = INVALID_SOCKET, ClientSocket = INVALID_SOCKET;
sockaddr_in LocalAddr,remote_addr;
int iResult = 0;
int Addrlen = 0;
HANDLE hThread = NULL;
//Initiate
iResult = WSAStartup(MAKEWORD(2, 2), &ws);
if (iResult != 0)
{
cout << "Initiate failed with error: " << WSAGetLastError() << endl;
return -1;
}
//create socket
ServerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ServerSocket == INVALID_SOCKET)
{
cout << "create socket failed with error: " << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
LocalAddr.sin_family = AF_INET;
LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDR);
LocalAddr.sin_port = htons(PORT);
LocalAddr.sin_addr.S_un.S_addr = INADDR_ANY;
memset(LocalAddr.sin_zero, 0x00, 8);
//bind socket
iResult = bind(ServerSocket, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr));
if (iResult != 0)
{
cout << "Bind socket failed: " << WSAGetLastError() << endl;
closesocket(ServerSocket);
WSACleanup();
return -1;
}
char Recvbuf[MAX_LEN];
int remote_len = sizeof(remote_addr);
cout << "UDP server started up!\n" << endl;
while (TRUE)
{
iResult = recvfrom(ServerSocket, Recvbuf, MAX_LEN, 0, (struct sockaddr *)&remote_addr, &remote_len);
if (iResult == SOCKET_ERROR || iResult == 0)
{
cout << "Receive data failed with error " << WSAGetLastError() << endl;
//每次如果出现任何错误,continue会回到这里,因为这个时候客户端已经关闭,就可以统一的closesocket关闭连接同时返回
return -1;
}
Recvbuf[iResult] = '\0';
struct inform para;
para.server = ServerSocket;
para.remote = remote_addr;
para.remote_len = remote_len;
para.data = Recvbuf;
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID*)¶, 0, NULL);
if (hThread == NULL)
{
cout << "Create Thread failed!" << endl;
break;
}
CloseHandle(hThread);
}
closesocket(ServerSocket);
WSACleanup();
system("pause");
return 0;
}
实验二
Client
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <stdlib.h>
#include <stdint.h>
#include <fstream>
#include<io.h>
#include <stdint.h>
using namespace std;
#pragma comment (lib,"ws2_32.lib")
using namespace std;
//缓存区长度
#define MAX_LEN 10000
int __cdecl main(int argc, char* argv[])
{
WSADATA ws;
SOCKET ClientSocket = INVALID_SOCKET;
struct sockaddr_in Server_addr,Confirm_addr;
int iResult = 0;
int Addrlen = 0;
HANDLE hThread = NULL;
char Recvbuffer[MAX_LEN + 2];
//检查参数个数
if (argc != 4)
{
cout << "Need enter target IP, port and the file name to transmit !" << endl;
return -1;
}
int PORT = atoi(argv[2]);
//初始化 socket
iResult = WSAStartup(MAKEWORD(2, 2), &ws);
if (iResult != 0)
{
cout << "Initiate failed with error: " << GetLastError() << endl;
return -1;
}
//创建 socket
ClientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ClientSocket == INVALID_SOCKET)
{
cout << "Create Client socket failed with error: " << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
Server_addr.sin_family = AF_INET;
Server_addr.sin_addr.s_addr = inet_addr(argv[1]);
Server_addr.sin_port = htons(PORT);
memset(Server_addr.sin_zero, 0x00, 8);
int Server_addr_len = sizeof(Server_addr);
char filebuf[MAX_LEN + 1]; //文件内容存储数组
//确定文件的大小
int len;
FILE* fp;
if (fp = fopen(argv[3], "r"))
{
fseek(fp, 0, SEEK_END);
printf("%ld\n", ftell(fp));
len = ftell(fp);
fclose(fp);
}
else
{
cout << "Error to get the size of file\n" << endl;
cout << "Client exit." << endl;
closesocket(ClientSocket);
WSACleanup();
return -1;
}
//设置超时时间
int nTimeOver = 10000;
setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeOver, sizeof(nTimeOver));
//传输文件,先传输文件名,再传输文件长度,最后传输文件内容
cout << "########################################## File Information ##########################################" << endl;
int len3 = strlen(argv[3]);
//对文件名传输进行处理
char filename[MAX_PATH];
int i = 0;
for (i = 0; i < len3; i++)
{
filename[i] = argv[3][i];
}
filename[i++] = '#';
filename[i++] = '\0';
//传输文件名
iResult = sendto(ClientSocket, filename, strlen(filename), 0,(sockaddr*)&Server_addr,Server_addr_len);
if (iResult != strlen(filename) || iResult >= MAX_PATH)
{
cout << "Sending filename with error :" << WSAGetLastError() << endl;
cout << "Client exit." << endl;
closesocket(ClientSocket);
WSACleanup();
return -1;
}
cout << "Sending filename to ( " << inet_ntoa(Server_addr.sin_addr) << " : " << Server_addr.sin_port<<" ) " << endl;
//获取传输地址信息,端口
sockaddr_in trans_addr;
int trans_addr_len=sizeof(trans_addr);
iResult = recvfrom(ClientSocket, Recvbuffer, MAX_LEN, 0, (struct sockaddr *)&trans_addr, &trans_addr_len);
Recvbuffer[iResult] = '\0';
if (strcmp(Recvbuffer,"Ready to receive file!")!=0)
{
cout << "Error: " << WSAGetLastError() << endl;
cout << "Unable to assure the port to send file!\n" << endl;
closesocket(ClientSocket);
WSACleanup();
system("pause");
return -1;
//break;
}
else
{
cout << "File transfer to ( " << inet_ntoa(trans_addr.sin_addr) << " : " << trans_addr.sin_port <<" ) "<< endl;
}
//以二进制文件形式读取文件
ifstream sourcefile(argv[3], ios::in | ios::binary);
int filelen = len;
int filelen_net = htonl(filelen);
//传输内容长度
cout << "Sending the length of file : " << filelen << "\n" << endl;
iResult = sendto(ClientSocket, (char*)&filelen_net, 4, 0,(sockaddr*)&trans_addr,trans_addr_len);
if (iResult == SOCKET_ERROR)
{
cout << "Send file length failed with error " << WSAGetLastError() << endl;
closesocket(ClientSocket);
WSACleanup();
system("pause");
return -1;
}
//传输文件内容
cout << "########################################## Sending file ##########################################" << endl;
int left = filelen;
int mode = 0;
while (left > 0)
{
if (left > MAX_LEN)
{
mode = MAX_LEN;
}
else
{
mode = left;
}
sourcefile.read(filebuf, mode);
iResult = sendto(ClientSocket, filebuf, mode, 0, (sockaddr*)&trans_addr, trans_addr_len);
if (iResult == SOCKET_ERROR)
{
cout << "Send file content failed with error " << WSAGetLastError() << "\n" << endl;
break;
}
left -= mode;
cout << "Sending Bytes: " << mode << endl;
Sleep(100);
}
sourcefile.close();
if (left != 0)
{
cout << "Send file content failed with error " << WSAGetLastError() << "\n" << endl;
cout << "Client Exit..." << endl;
closesocket(ClientSocket);
WSACleanup();
system("pause");
return -1;
}
//判断来自客户端的返回信息
cout << "########################################## Confirm information ##########################################\n" << endl;
int Confirm_addr_len = sizeof(Confirm_addr);
iResult = recvfrom(ClientSocket, Recvbuffer, MAX_LEN, 0, (sockaddr *)&Confirm_addr, &Confirm_addr_len);
Recvbuffer[iResult] = '\0';
if (iResult > 0)
{
cout << "Receive information from server ( " << inet_ntoa(Confirm_addr.sin_addr)<<" : "<<Confirm_addr.sin_port<<" )\n" << endl;
}
cout << "########################################## Exit ##########################################" << endl;
closesocket(ClientSocket);
WSACleanup();
system("pause");
return 0;
}
Server
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <stdlib.h>
#include <stdint.h>
#include <fstream>
using namespace std;
#pragma comment (lib,"ws2_32.lib")
#define PORT 4000
#define IP_ADDR "0.0.0.0"
#define MAX_LEN 10000
//自己定义的结构体,用于多线程传参
struct inform
{
SOCKET server;
sockaddr_in remote;
int remote_len;
char *data;
};
int newport = 4500;
//多线程函数
DWORD WINAPI ClientThread(LPVOID lpparameter)
{
struct inform para = *(struct inform *)lpparameter;
int iResult = 0;
char RecvBuffer[MAX_LEN];
//传参处理
SOCKET ConnectSocket = (SOCKET)para.server;
SOCKET TransSocket = INVALID_SOCKET;
sockaddr_in remote = para.remote;
int remote_len = para.remote_len;
char *data = para.data;
int filelength = 0;
char filename[MAX_PATH] = { 0 };
//对于传输的文件名进行处理
int cnt = 0;
while (data[cnt] != '#')
{
filename[cnt] = data[cnt];
cnt++;
}
filename[cnt] = '\0';
char connectmessage[] = "Ready to receive file!";
//创建一个新的socket
TransSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (TransSocket == INVALID_SOCKET)
{
cout << "Create Transfer socket failed with error: " << WSAGetLastError() << endl;
return -1;
}
sockaddr_in newaddr;
newaddr.sin_family = AF_INET;
newaddr.sin_addr.s_addr = inet_addr(IP_ADDR);
newaddr.sin_addr.S_un.S_addr = INADDR_ANY;
memset(newaddr.sin_zero, 0x00, 8);
int newaddr_len = sizeof(newaddr);
//bind socket,一个新的端口
iResult = bind(TransSocket, (struct sockaddr *)&newaddr, newaddr_len);
if (iResult != 0)
{
cout << "Bind socket failed: " << WSAGetLastError() << endl;
closesocket(TransSocket);
return -1;
}
//设置超时时间
int nTimeOver = 10000;
setsockopt(TransSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeOver, sizeof(nTimeOver));
//用新的socket给client发送确认信息,后续传输用新的socket
//如果确认失败,退出
iResult = sendto(TransSocket, connectmessage, strlen(connectmessage), 0, (sockaddr*)&remote, remote_len);
if (iResult == SOCKET_ERROR)
{
cout << "Return confirm message with error " << WSAGetLastError() << endl;
cout << "Unable for client to transfer with a new socket." << endl;
cout << "Exit!\n" << endl;
closesocket(TransSocket);
return -1;
}
cout << "Ready to receive file!\n" << endl;
//接收文件长度数据
int len_tran = 0;
iResult = recvfrom(TransSocket, (char*)&len_tran, 4, 0, (sockaddr*)&remote, &remote_len);
if (iResult != 4)
{
if (iResult == -1)
{
cout << "Receive failed with error " << WSAGetLastError() << endl;
closesocket(TransSocket);
return -1;
}
else
{
cout << "Length data is not complete. Connection closed\n" << endl;
closesocket(TransSocket);
return -1;
}
}
int recvlen = ntohl(len_tran);
cout << "The length of file to receive is " << recvlen << "\n" << endl;
//创建文件
ofstream rec_file;
rec_file.open(filename, ios::binary);
int left = recvlen;
int mode = 0;
while (left > 0)
{
if (left >= MAX_LEN)
{
mode = MAX_LEN;
}
else
{
mode = left;
}
iResult = recvfrom(TransSocket, RecvBuffer, mode, 0, (sockaddr*)&remote, &remote_len);;
if (iResult == -1)
{
cout << "Receive failed with error " << WSAGetLastError() << endl;
break;
}
else if (iResult == 0)
{
cout << "Receive data stopped. There " << left << " bytes unreceived" << endl;
break;
}
else
{
rec_file.write(RecvBuffer, mode);
cout << "Receive data : " << iResult << " bytes" << endl;
}
left -= mode;
cout << " There " << left << " bytes unreceived\n" << endl;
}
if (left == 0)
{
cout << "Receive all the data\n" << endl;
char returnmessage[] = "OK\0";
iResult = sendto(TransSocket, returnmessage, strlen(returnmessage), 0, (sockaddr*)&remote, remote_len);
if (iResult == SOCKET_ERROR)
{
cout << "Return confirm message with error " << WSAGetLastError() << endl;
cout << "End!\n" << endl;
closesocket(TransSocket);
return -1;
}
else
{
cout << "Return success!\n" << endl;
cout << "######################################################## End ########################################################\n\n" << endl;
}
}
else
{
cout << "File transfer is too vulnerable!\n" << endl;
cout << "End!\n" << endl;
closesocket(TransSocket);
return -1;
}
rec_file.close();
closesocket(TransSocket);
return 0;
}
int main(int argc, char * argv[])
{
WSADATA ws;
SOCKET ServerSocket = INVALID_SOCKET, ClientSocket = INVALID_SOCKET;
sockaddr_in LocalAddr, ClientAddr;
int iResult = 0;
int Addrlen = 0;
HANDLE hThread = NULL;
//Initiate
iResult = WSAStartup(MAKEWORD(2, 2), &ws);
if (iResult != 0)
{
cout << "Initiate failed with error: " << WSAGetLastError() << endl;
return -1;
}
//create socket
ServerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ServerSocket == INVALID_SOCKET)
{
cout << "create socket failed with error: " << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
LocalAddr.sin_family = AF_INET;
LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDR);
LocalAddr.sin_port = htons(PORT);
LocalAddr.sin_addr.S_un.S_addr = INADDR_ANY;
memset(LocalAddr.sin_zero, 0x00, 8);
//bind socket
iResult = bind(ServerSocket, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr));
if (iResult != 0)
{
cout << "Bind socket failed: " << WSAGetLastError() << endl;
closesocket(ServerSocket);
WSACleanup();
return -1;
}
cout << "UDP Server is already setup!\n" << endl;
char Recvbuf[MAX_LEN + 1];
int ClientAddr_len;
sockaddr_in remote_addr;
int remote_len = sizeof(remote_addr);
while (TRUE)
{
iResult = recvfrom(ServerSocket, Recvbuf, MAX_LEN, 0, (struct sockaddr *)&remote_addr, &remote_len);
if (iResult == SOCKET_ERROR || iResult == 0)
{
cout << "Receive data failed with error " << WSAGetLastError() << endl;
//每次如果出现任何错误,continue会回到这里,因为这个时候客户端已经关闭,就可以统一的closesocket关闭连接同时返回
continue;
}
Recvbuf[iResult] = '\0';
struct inform para;
para.server = ServerSocket;
para.remote = remote_addr;
para.remote_len = remote_len;
para.data = Recvbuf;
cout << "################################################ Connect with client ##################################################" << endl;
cout << "IP address: " << inet_ntoa(remote_addr.sin_addr) << " port: " << remote_addr.sin_port << endl;
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID*)¶, 0, NULL);
if (hThread == NULL)
{
cout << "Create Thread failed!" << endl;
break;
}
CloseHandle(hThread);
}
closesocket(ServerSocket);
// closesocket(ClientSocket);
WSACleanup();
system("pause");
return 0;
}
ss