基于数据报套接字的服务器回射程序设计内容:
编写一服务器程序和客户程序,如图1,要求客户每输入一行数据,服务器接收后加上echo:回送给客户程序,当客户输入“q”后退出。
为了解决接收客户端的多次交互的请求的问题,在客户端发出第一个“ASK Port”请求后服务器为每个客户创建一个的新的套接字,在其上 bind 一个临时端口,创建一个子进程使用该套接字发送对该客户的所有应答。要求客户端查看服务器第一个应答的中的源端口号,并把本请求的后续数据报发送到该端口。
#define NETWORK1_2_1_A_COMM_H
#define NETWORK1_2_1_A_COMM_H
#include
#include
#include
#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
#define MAXLINE 4096 // 接收缓冲区长度
#define LISTENQ 1024 // 监听队列长度
#define SEVER_PORT 13442 // 端口
/*套接字初始化*/
int StartUp()
{
WORD w_version = MAKEWORD(2, 2);
WSADATA wsa_data;
int res = WSAStartup(w_version, &wsa_data);
if (res != 0)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
return -1;
}//版本号错误
if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
WSACleanup();
return -1;
}
return 0; //成功返回0
}
/*释放资源*/
int cleanUp()
{
int res = WSACleanup();
if (res == SOCKET_ERROR)
{
printf("WSACleanup Error:%d",WSAGetLastError());
return -1;
}
return 0;
}
/*断开连接,释放资源*/
int closeConn(SOCKET sock_conn)
{
int res = closesocket(sock_conn); //关闭连接
if (res == SOCKET_ERROR)
{
printf("关闭连接失败%d\n",WSAGetLastError());
return -1;
}
res = cleanUp();
return res;
}
/*连接服务器并绑定*/
SOCKET udpClientInit(char *server_ip, u_short port, sockaddr_in &server_addr, bool flag)
{
int res = -1;
SOCKET sock_conn;
// 绑定地址、端口
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.S_un.S_addr = inet_addr(server_ip);
//创建套接字
sock_conn = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_conn == INVALID_SOCKET)
{
printf("连接初始化失败%d\n",WSAGetLastError());
cleanUp();
return -1;
}
if (flag)
{
// 请求连接服务器
res = connect(sock_conn, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (res == SOCKET_ERROR)
{
// 连接服务器失败
printf("连接失败:%d\n",WSAGetLastError());
closeConn(sock_conn);
return -1;
}
}
return sock_conn; //连接成功
}
int getline(char s[],int lim)
{
int c,i;
i=0;
while((c=getchar())!=EOF&&c!='\n'&&i<lim-1)
s[i++]=c;
s[i]='\0';
return i;
}
/*回射客户端发送接收程序*/
int udpEchoClient(SOCKET sock_conn, SOCKADDR *server_addr, int addr_len)
{
int res = -1;
char send_data[MAXLINE], recv_data[MAXLINE];
memset(send_data, 0, MAXLINE);
memset(recv_data, 0, MAXLINE);
while (getline(send_data, MAXLINE))//输入缓冲区接收一行数据
{
// 结束
if (*send_data == 'Q' || *send_data == 'q')
{
puts("退出");
return 0; // 正常退出
}
// 发送数据
res = sendto(sock_conn, send_data, (int)strlen(send_data), 0, (SOCKADDR *)server_addr, addr_len);
if (res == SOCKET_ERROR)
{
printf("发送失败:%d\n",WSAGetLastError());
return -1;
}
printf("发送数据:%s\n",send_data);
// 接收数据
res = recvfrom(sock_conn, recv_data, MAXLINE, 0, NULL, NULL);
if (res > 0)
{
printf("接收到的数据:%s\n",recv_data);
}
else
{
printf("接收失败:%d\n",WSAGetLastError());
break;
}
// 清空缓存
memset(recv_data, 0, MAXLINE);
memset(send_data, 0, MAXLINE);
}
return res;
}
int main()
{
int res = -1;
SOCKET sock_conn;
struct sockaddr_in server_addr;
char server_ip[] = "10.236.10.200";
res = StartUp();//初始化动态连接库
if (res == -1) return -1;
sock_conn = udpClientInit(server_ip, SEVER_PORT, server_addr, true);//连接初始化
if (sock_conn == -1) return -1;
puts("连接服务器成功");
res = udpEchoClient(sock_conn, (SOCKADDR *)&server_addr, sizeof(sockaddr_in));
if (res == -1)puts("Error");
closeConn(sock_conn);
return res;
}
//回射程序,服务器段端,循环服务器
#define NETWORK1_2_1_A_COMM_H
#define NETWORK1_2_1_A_COMM_H
#include
#include
#include
#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
#define MAXLINE 4096 // 接收缓冲区长度
#define LISTENQ 1024 // 监听队列长度
#define SEVER_PORT 13442 // 端口
/*套接字初始化*/
int StartUp()
{
WORD w_version = MAKEWORD(2, 2);
WSADATA wsa_data;
int res = WSAStartup(w_version, &wsa_data);
if (res != 0)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
return -1;
}//版本号错误
if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
WSACleanup();
return -1;
}
return 0; //成功返回0
}
/*释放资源*/
int cleanUp()
{
int res = WSACleanup();
if (res == SOCKET_ERROR)
{
printf("WSACleanup Error:%d",WSAGetLastError());
return -1;
}
return 0;
}
/*断开连接,释放资源*/
int closeConn(SOCKET sock_conn)
{
int res = closesocket(sock_conn); //关闭连接
if (res == SOCKET_ERROR)
{
printf("关闭连接失败%d\n",WSAGetLastError());
return -1;
}
res = cleanUp();
return res;
}
/*服务器初始化*/
SOCKET udpServerInit(int port)
{
int res = -1;
SOCKET sock_listen;
const int on = 1;
// 绑定地址、端口
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
//创建监听套接字
sock_listen = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_listen == INVALID_SOCKET)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
cleanUp();
return -1;
}
//绑定服务器地址
res = bind(sock_listen, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (res == SOCKET_ERROR)
{
printf("绑定失败:%d\n",WSAGetLastError());
closeConn(sock_listen);
return -1;
}
return sock_listen;
}
/*循环服务器接收程序*/
int udpEchoServer(SOCKET sock_conn)
{
// 此处利用指针的移动 实现添加Echo
int res = -1;
char recv_data[MAXLINE];
struct sockaddr_in client_addr;
int addr_len = sizeof(client_addr);
do
{
// 清空缓存
memset(recv_data, 0, MAXLINE);
// 循环接收数据
res = recvfrom(sock_conn, recv_data , MAXLINE , 0, (SOCKADDR *)&client_addr, &addr_len);
if (res > 0)
{
printf("从客户端接受到数据:%s:\n",recv_data);
// 回射接收的数据
res = sendto(sock_conn, recv_data, res , 0, (SOCKADDR *)&client_addr, addr_len);
if (res == SOCKET_ERROR)
{
printf("sendto error:%d\n",WSAGetLastError());
res = -1;
}
else
{
printf("服务器回射数据:%s\n",recv_data);
}
}
else
{
printf("recvfrom error:%d\n",WSAGetLastError());
res = -1;
}
} while (res > 0);
return res;
}
int main(int argc, char *argv[])
{
int res = -1;
SOCKET sock_listen;
res = StartUp();//初始化
if (res == -1) return -1;//初始化失败
sock_listen = udpServerInit(SEVER_PORT);//创建监听套接字
if (sock_listen == -1) return -1;
puts("udpServerInit success") ;
//循环服务器
while (1)
{
// 回射 如果出错,继续其他客户端请求
res = udpEchoServer(sock_listen);
if (res == -1) puts("cilent connectione error,continue to connect to the next client");
}
closeConn(sock_listen); // 关闭监听服务
return 0;
}
#define NETWORK1_2_1_A_COMM_H
#define NETWORK1_2_1_A_COMM_H
#include
#include
#include
#include
#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
#define MAXLINE 4096 // 接收缓冲区长度
#define LISTENQ 1024 // 监听队列长度
#define SEVER_PORT 13442 // 端口
/*套接字初始化*/
int StartUp()
{
WORD w_version = MAKEWORD(2, 2);
WSADATA wsa_data;
int res = WSAStartup(w_version, &wsa_data);
if (res != 0)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
return -1;
}//版本号错误
if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
WSACleanup();
return -1;
}
return 0; //成功返回0
}
/*释放资源*/
int cleanUp()
{
int res = WSACleanup();
if (res == SOCKET_ERROR)
{
printf("WSACleanup Error:%d",WSAGetLastError());
return -1;
}
return 0;
}
/*断开连接,释放资源*/
int closeConn(SOCKET sock_conn)
{
int res = closesocket(sock_conn); //关闭连接
if (res == SOCKET_ERROR)
{
printf("关闭连接失败%d\n",WSAGetLastError());
return -1;
}
res = cleanUp();
return res;
}
/*服务器初始化*/
SOCKET udpServerInit(int port)
{
int res = -1;
SOCKET sock_listen;
const int on = 1;
// 绑定地址、端口
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
//创建监听套接字
sock_listen = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_listen == INVALID_SOCKET)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
cleanUp();
return -1;
}
//绑定服务器地址
res = bind(sock_listen, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (res == SOCKET_ERROR)
{
printf("绑定失败:%d\n",WSAGetLastError());
closeConn(sock_listen);
return -1;
}
return sock_listen;
}
/*子线程,线程函数*/
void* ThreadUdpEchoServer(LPVOID pParam){
// 此处利用指针的移动 实现添加Echo
int sock_res;
char recv_data[MAXLINE];
struct sockaddr_in client_addr;
int addr_len = sizeof(client_addr);
// 将输入参数转换成连接套接字
SOCKET sock_conn = *((SOCKET *) pParam);
do {
memset(recv_data, 0, MAXLINE);
// 接收数据
sock_res = recvfrom(sock_conn, recv_data, MAXLINE, 0, (SOCKADDR *) &client_addr, &addr_len);
if (sock_res > 0) {
printf("从客户端接收到的数据:%s\n",recv_data);
// 回射接收的数据
sock_res = sendto(sock_conn, recv_data, sock_res, 0, (SOCKADDR *) &client_addr, addr_len);
if (sock_res == SOCKET_ERROR) {
printf("sendto error:%d\n",WSAGetLastError());
sock_res = -1;
} else {
printf("发送出的数据:%s\n",recv_data);
}
} else {
printf("recvfrom error:%d\n",WSAGetLastError());
sock_res = -1;
}
} while (sock_res > 0);
// 出错,继续其他客户端请求
if (sock_res == -1) puts("此用户连接出错,继续下一个连接...");
return NULL;
}
/*并发服务器*/
int UdpServer(SOCKET sock_conn){
int sock_res;
char recv_data[MAXLINE];
struct sockaddr_in client_addr;
int addr_len = sizeof(client_addr);
SOCKET sock_child;
struct sockaddr_in server_addr;
const int on = 1;
HANDLE hThread;
do {
memset(recv_data, 0, MAXLINE);
// 接收数据
sock_res = recvfrom(sock_conn, recv_data, MAXLINE, 0, (SOCKADDR *) &client_addr, &addr_len);
if (sock_res > 0) {
printf("接收到的数据:%s\n",recv_data);
// 回射接收的数据
// 创建一个新的socket
// 设置地址、端口
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = 0;
//创建套接字
sock_child = socket(AF_INET, SOCK_DGRAM, 0);
// 创建失败
if (sock_child == INVALID_SOCKET) {
printf("sock_child error:%d\n",WSAGetLastError());
cleanUp();
return -1;
}
//绑定服务器地址
sock_res = bind(sock_child, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (sock_res == SOCKET_ERROR) {
printf("bind error:%d\n",WSAGetLastError());
closeConn(sock_child);
return -1;
}
// 获取端口号
struct sockaddr_in temp_conn;
int temp_len = sizeof(temp_conn);
sock_res = getsockname(sock_child, (SOCKADDR*)&temp_conn, &temp_len);
if (sock_res != 0){
puts("getsockname error");
return -1;
}
int port = ntohs(temp_conn.sin_port);
memset(recv_data, 0, MAXLINE);
itoa(port, recv_data, 10);
sock_res = sendto(sock_conn, recv_data, (int)strlen(recv_data), 0, (SOCKADDR *) &client_addr, addr_len);
if (sock_res == SOCKET_ERROR) {
printf("sendto error:%d\n",WSAGetLastError());
sock_res = -1;
} else {
printf("发送出的数据:%s\n",recv_data);
hThread=CreateThread(NULL,0,ThreadUdpEchoServer,&sock_child,0,NULL);
return 0;
}
} else {
printf("recvfrom error:%d\n",WSAGetLastError());
sock_res = -1;
}
} while (sock_res > 0);
// 出错,继续其他客户端请求
if (sock_res == -1)
{
CloseHandle(hThread);
puts("此用户连接出错,继续下一个连接...");
}
return 0;
}
int main(int argc, char *argv[]) {
int sock_res;
SOCKET sock_listen;
HANDLE hThread;
if (StartUp() == -1) return -1; // 启动
sock_listen = udpServerInit(SEVER_PORT); //监听
if (sock_listen == -1) return -1;
puts("udpServerInit success");
while (1) {
sock_res = UdpServer(sock_listen);
// 出错,继续其他客户端请求
if (sock_res == -1) puts("此用户连接出错,继续下一个连接...");
}
CloseHandle(hThread);
// 关闭监听服务
closeConn(sock_listen);
return 0;
}
//回射程序,并发服务器对应的客户端
#define NETWORK1_2_1_A_COMM_H
#define NETWORK1_2_1_A_COMM_H
#include
#include
#include
#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
#define MAXLINE 4096 // 接收缓冲区长度
#define LISTENQ 1024 // 监听队列长度
#define SEVER_PORT 13442 // 端口
char server_ip[] = "10.236.10.200";
/*套接字初始化*/
int StartUp()
{
WORD w_version = MAKEWORD(2, 2);
WSADATA wsa_data;
int res = WSAStartup(w_version, &wsa_data);
if (res != 0)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
return -1;
}//版本号错误
if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
WSACleanup();
return -1;
}
return 0; //成功返回0
}
/*释放资源*/
int cleanUp()
{
int res = WSACleanup();
if (res == SOCKET_ERROR)
{
printf("WSACleanup Error:%d",WSAGetLastError());
return -1;
}
return 0;
}
/*断开连接,释放资源*/
int closeConn(SOCKET sock_conn)
{
int res = closesocket(sock_conn); //关闭连接
if (res == SOCKET_ERROR)
{
printf("关闭连接失败%d\n",WSAGetLastError());
return -1;
}
res = cleanUp();
return res;
}
int getline(char s[],int lim)
{
int c,i;
i=0;
while((c=getchar())!=EOF&&c!='\n'&&i<lim-1)
s[i++]=c;
s[i]='\0';
return i;
}
/*回射客户端发送接收程序*/
int udpEchoClient(SOCKET sock_conn, SOCKADDR *server_addr, int addr_len)
{
int res = -1;
char send_data[MAXLINE], recv_data[MAXLINE];
memset(send_data, 0, MAXLINE);
memset(recv_data, 0, MAXLINE);
while (getline(send_data, MAXLINE))//输入缓冲区接收一行数据
{
// 结束
if (*send_data == 'Q' || *send_data == 'q')
{
puts("退出");
return 0; // 正常退出
}
// 发送数据
res = sendto(sock_conn, send_data, (int)strlen(send_data), 0, (SOCKADDR *)server_addr, addr_len);
if (res == SOCKET_ERROR)
{
printf("发送失败:%d\n",WSAGetLastError());
return -1;
}
printf("发送数据:%s\n",send_data);
// 接收数据
res = recvfrom(sock_conn, recv_data, MAXLINE, 0, NULL, NULL);
if (res > 0)
{
printf("接收到的数据:%s\n",recv_data);
}
else
{
printf("接收失败:%d\n",WSAGetLastError());
break;
}
// 清空缓存
memset(recv_data, 0, MAXLINE);
memset(send_data, 0, MAXLINE);
}
return res;
}
/*连接服务器并绑定*/
SOCKET udpClientInit(char *server_ip, u_short port, sockaddr_in &server_addr, bool flag)
{
int res = -1;
SOCKET sock_conn;
// 绑定地址、端口
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.S_un.S_addr = inet_addr(server_ip);
//创建套接字
sock_conn = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_conn == INVALID_SOCKET)
{
printf("连接初始化失败%d\n",WSAGetLastError());
cleanUp();
return -1;
}
if (flag)
{
// 请求连接服务器
res = connect(sock_conn, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (res == SOCKET_ERROR)
{
// 连接服务器失败
printf("连接失败:%d\n",WSAGetLastError());
closeConn(sock_conn);
return -1;
}
}
return sock_conn; //连接成功
}
/*对应并发服务器,客户端请求新端口函数*/
int UdpClientAskNewPort(SOCKET sock_conn, sockaddr_in server_addr, int addr_len){
int sock_res;
char send_data[MAXLINE] = "ASK port", recv_data[MAXLINE];
memset(recv_data, 0, MAXLINE);
while (1) {
sock_res = sendto(sock_conn, send_data, (int) strlen(send_data), 0, (SOCKADDR *)&server_addr, addr_len);
if (sock_res == SOCKET_ERROR) {
printf("ASK port send error:%d\n",WSAGetLastError());
return -1;
}
memset(recv_data, 0, MAXLINE);
sock_res = recvfrom(sock_conn, recv_data, MAXLINE, 0, NULL, NULL);
if (sock_res > 0) {
printf("Requset :接收到的新端口号为:%s\n",recv_data);
//客户端重新连接
sock_conn = udpClientInit(server_ip, (u_short) atoi(recv_data), server_addr, true);
if (sock_conn == -1)
{
puts("客户端重新连接新端口失败");
return -1;
}
sock_res = udpEchoClient(sock_conn, (SOCKADDR *)&server_addr, addr_len);
if (sock_res == -1) puts("客户端连接失败");
closeConn(sock_conn);
break;
} else {
printf("recv error:%d\n",WSAGetLastError());
return -1;
}
}
return 0;
}
int main() {
int sock_res;
SOCKET sock_conn;
sockaddr_in server_addr;
if (StartUp() == -1) return -1; // 启动
sock_conn = udpClientInit(server_ip, SEVER_PORT, server_addr, true); //连接
if (sock_conn == -1) return -1;
// 连接服务器成功
puts("客户端启动");
sock_res = UdpClientAskNewPort(sock_conn, server_addr, sizeof(sockaddr_in));
if (sock_res == -1) puts("连接失败");
closeConn(sock_conn);
return sock_res;
}
对回射服务器和客户端(循环服务器以及并发服务器):