基于TCP/IP的迭代回声服务器/客户端
2017-04-17 12:11
501 查看
服务器/客户端的实现顺序:
需要注意的是:客户端只有等到服务器调用listen函数后才能调connect函数。同时要清楚,客户端调用connect函数前,服务器端有可能率先调用accept函数。当然,此时服务器在调用accept函数时进入阻塞状态,直到客户端调用connect函数为止。
迭代服务器/客户端:
插入循环语句反复调用accept函数,图示如下简单的迭代服务器/客户端代码:
服务器
//服务器代码 #include<stdlib.h> #include<stdio.h> #include<WinSock2.h> #pragma comment(lib,"ws2_32.lib") //显示调用ws2_32.lib void ErrorHanding(char* message); int main() { WSADATA wsadata; SOCKET hserverSocket, hclientSocket; SOCKADDR_IN serveraddr, clientaddr; int szClientAdd,str_len; char message[4096] = "\0"; if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) //初始化winsock库 ErrorHanding("WSAStartup() error"); hserverSocket = socket(PF_INET, SOCK_STREAM, 0); // IPV4 面向连接传输 if (hserverSocket == INVALID_SOCKET) ErrorHanding("socket() error"); memset(&serveraddr, 0, sizeof(serveraddr));//清空,值全为0 serveraddr.sin_family = AF_INET; //IPv4 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //自动寻找本机地址 serveraddr.sin_port = htons(6666); //端口为 6666 //绑定服务器地址 if (bind(hserverSocket, (SOCKADDR*)&serveraddr, sizeof(serveraddr)) == SOCKET_ERROR) ErrorHanding("bind() error"); printf("服务器启动成功.........\n"); //使套接字成为服务器套接字 if (listen(hserverSocket,5) == SOCKET_ERROR) { //等待队列的最大数目为5 ErrorHanding("listen() error"); } szClientAdd = sizeof(clientaddr); for (int i = 0; i < 5; i++) { hclientSocket = accept(hserverSocket, (SOCKADDR*)&clientaddr, &szClientAdd); if (hclientSocket == INVALID_SOCKET) ErrorHanding("accept() Error"); printf("这是客户端: NO . %d\n", i + 1); closesocket(hclientSocket); //关闭客户套接字 } getchar(); closesocket(hserverSocket); //关闭服务器套接字 WSACleanup(); //清理winsock库 return 0; } void ErrorHanding(char* message) { fputs(message, stderr); fputc('\n', stderr); }
客户端
#include<stdlib.h> #include<stdio.h> #include<WinSock2.h> #pragma comment(lib,"ws2_32.lib") void ErrorHanding(char* message); int main() { WSADATA wsadata; SOCKET hclientsocket; SOCKADDR_IN servAddr; char message[30]; int strlen; if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) ErrorHanding("WSAStartup() error"); hclientsocket = socket(PF_INET, SOCK_STREAM, 0); if (hclientsocket == INVALID_SOCKET) ErrorHanding("socket() error"); memset(&servAddr, 0, sizeof(servAddr)); servAddr.sin_family = AF_INET; servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //回送地址,访问本地 servAddr.sin_port = htons(6666); //端口号 printf("客户端启动成功.......\n"); //客户端套接字通过目的地址建立连接 if (connect(hclientsocket, (SOCKADDR*)&servAddr, sizeof(servAddr))) ErrorHanding("conect() error"); getchar(); closesocket(hclientsocket); WSACleanup(); return 0; } void ErrorHanding(char* message) { fputs(message, stderr); fputc('\n', stderr); }
每次客户端打开,获取任意字符后结束,服务器都能接收到消息,但是只能相应5次,获取任意字符后就关闭了,当然这只是为了了解原理而写,非常简单,不能识别同一客户端,
迭代回声服务器/客户端:
程序的基本运行方式如下1)服务器在同一时刻只与一个客户端相连,并提供回声服务。
2)服务器依次向5个客户端提供服务并退出
3)客户端接受用户输入的字符串并发送到服务器端
4)服务器端将接收的自负出汗数据传回客户端,即“回声”
5)服务器端与客户端之间的字符串回声一直执行到客户端输入Q为止
服务器:
//服务器代码 #include<stdlib.h> #include<stdio.h> #include<WinSock2.h> #pragma comment(lib,"ws2_32.lib") //显示调用ws2_32.lib void ErrorHanding(char* message); int main() { WSADATA wsadata; SOCKET hserverSocket, hclientSocket; SOCKADDR_IN serveraddr, clientaddr; int szClientAdd,str_len; char message[4096] = "\0"; if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) //初始化winsock库 ErrorHanding("WSAStartup() error"); hserverSocket = socket(PF_INET, SOCK_STREAM, 0); // IPV4 面向连接传输 if (hserverSocket == INVALID_SOCKET) ErrorHanding("socket() error"); memset(&serveraddr, 0, sizeof(serveraddr));//清空,值全为0 serveraddr.sin_family = AF_INET; //IPv4 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //自动寻找本机地址 serveraddr.sin_port = htons(6666); //端口为 6666 //绑定服务器地址 if (bind(hserverSocket, (SOCKADDR*)&serveraddr, sizeof(serveraddr)) == SOCKET_ERROR) ErrorHanding("bind() error"); printf("服务器启动成功.........\n"); //使套接字成为服务器套接字 if (listen(hserverSocket,5) == SOCKET_ERROR) { //等待队列的最大数目为5 ErrorHanding("listen() error"); } szClientAdd = sizeof(clientaddr); for (int i = 0; i < 5; i++) { hclientSocket = accept(hserverSocket, (SOCKADDR*)&clientaddr, &szClientAdd); if (hclientSocket == INVALID_SOCKET) ErrorHanding("accept() Error"); printf("这是客户端: NO . %d\n", i + 1); while ((str_len = recv(hclientSocket, message, sizeof(message), 0)) != 0) { printf("%s", message); if (send(hclientSocket, message, str_len, 0) == SOCKET_ERROR) { ErrorHanding("send() error"); break; } memset(message, '\0', sizeof(message)); } closesocket(hclientSocket); //关闭客户套接字 } getchar(); closesocket(hserverSocket); //关闭服务器套接字 WSACleanup(); //清理winsock库 return 0; } void ErrorHanding(char* message) { fputs(message, stderr); fputc('\n', stderr); }
客户端:
#include<stdlib.h> #include<string.h> #include<stdio.h> #include<WinSock2.h> #pragma comment(lib,"ws2_32.lib") void ErrorHanding(char* message); #define bufsize 100 int main() { WSADATA wsadata; SOCKET hclientsocket; SOCKADDR_IN servAddr; char message[bufsize]; int str_len=0; if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) ErrorHanding("WSAStartup() error"); hclientsocket = socket(PF_INET, SOCK_STREAM, 0); if (hclientsocket == INVALID_SOCKET) ErrorHanding("socket() error"); memset(&servAddr, 0, sizeof(servAddr)); servAddr.sin_family = AF_INET; servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //回送地址,访问本地 servAddr.sin_port = h bfe0 tons(6666); //端口号 printf("客户端启动成功.......\n"); //客户端套接字通过目的地址建立连接 if (connect(hclientsocket, (SOCKADDR*)&servAddr, sizeof(servAddr))) ErrorHanding("conect() error"); while (1) { printf("输入Q退出:"); fgets(message, bufsize, stdin); if (!strcmp(message, "q\n") || !strcmp(message, "Q\n")) break; send(hclientsocket, message, strlen(message), 0); memset(message, '\0', sizeof(message)); str_len = recv(hclientsocket, message, bufsize - 1, 0); if (str_len == SOCKET_ERROR) ErrorHanding("recv() error\n"); printf("服务器消息:%s", message); } closesocket(hclientsocket); WSACleanup(); return 0; } void ErrorHanding(char* message) { fputs(message, stderr); fputc('\n', stderr); }
上面客户端代码存在一点问题,TCP传输的数据不存在数据边界,如果传输数据大,经过多个路由器的转发后,recv函数执行第一次收到的字符串长度会小于实际发送的长度。
改进的客户端代码:
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
void ErrorHanding(char* message);
#define bufsize 2048
int main() {
WSADATA wsadata;
SOCKET hclientsocket;
SOCKADDR_IN servAddr;
char message[bufsize]="\0";
int str_len=0,rec_cnt,rec_len;
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
ErrorHanding("WSAStartup() error");
hclientsocket = socket(PF_INET, SOCK_STREAM, 0);
if (hclientsocket == INVALID_SOCKET)
ErrorHanding("socket() error");
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //回送地址,访问本地
servAddr.sin_port = htons(6666); //端口号
printf("客户端启动成功.......\n");
//客户端套接字通过目的地址建立连接
if (connect(hclientsocket, (SOCKADDR*)&servAddr, sizeof(servAddr)))
ErrorHanding("conect() error");
while (1) {
printf("输入Q退出:");
fgets(message, bufsize, stdin);
if (!strcmp(message, "q\n") || !strcmp(message, "Q\n")) break;
str_len = send(hclientsocket, message, strlen(message), 0);
memset(message, '\0', sizeof(message));
//保证数据传输的完整性
rec_len = 0;
while (rec_len < str_len) {
rec_cnt = recv(hclientsocket, &message[rec_len], bufsize - 1, 0);
if (rec_cnt == SOCKET_ERROR) ErrorHanding("recv() error\n");
rec_len += rec_cnt;
}
/*str_len = recv(hclientsocket, message, bufsize - 1, 0);
if (str_len == SOCKET_ERROR) ErrorHanding("recv() error\n");*/
printf("服务器消息:%s", message);
}
closesocket(hclientsocket);
WSACleanup();
return 0;
}
void ErrorHanding(char* message) {
fputs(message, stderr);
fputc('\n', stderr);
}
相关文章推荐
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- 基于TCP的迭代回声服务器端和客户端
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- Linux基于TCP/IP简单的客户端、服务器通信程序实例
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- Linux基于TCP/IP简单的客户端、服务器通信程序实例
- TCP/IP回声服务器客户端
- 基于Windows的迭代回声服务器端/客户端(基于TCP的服务器端/客户端)
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- C++基于TCP/IP简单的客户端、服务器通信程序实例