文章目录
服务器端完整代码客户端完整代码服务器/客户端运行效果:
本程序代码基于 《windows网络编程》 5.4 编程举例 修改所得。
程序功能: 向指定服务器发起连接请求,与服务器之间实现收发数据,然后关闭连接。客户端实现用户输入信息方式与服务器对话。
1)使用基本的服务器编程模式,创建流式套接字,根据指定的端口号绑定服务,建立监听队列,并接受来自客户端的连接请求,收发数据;使用基本的客户端编程模式,能够创建流式套接字,通过用户指定的服务器地址 。 2)通过改进服务器端,实现服务器循环为多个客户端提供服务;服务器端能够实现显示对应客户端的ip地址; 3)采用Windows环境下多线程开发方法改进服务器端,对每个客户连接请求独立创建通信线程;实现并发服务
注:这里规定客户端向服务器发送数据的格式为[长度]+[数据]。 比如,我们在客户端输入 “abcd”,实际发送是“9abcd”。 另外,在服务器端定义的缓冲区长度为10(#define DEFAULT_BUFLEN 10),而我们使用该缓冲区接收数据时使用循环接收的方式,以便能够全部接收来自客户端的信息。
服务器端完整代码
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <thread>
using std
::thread
;
#pragma warning(disable:4996)
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 10
#define DEFAULT_PORT "27015"
void task_connect(SOCKET
, struct sockaddr_in
);
void Print_SerIP();
int __cdecl
main(void)
{
WSADATA wsaData
;
int iResult
;
SOCKET ListenSocket
= INVALID_SOCKET
;
SOCKET ClientSocket
= INVALID_SOCKET
;
struct addrinfo
* result
= NULL;
struct addrinfo hints
;
iResult
= WSAStartup(MAKEWORD(2, 2), &wsaData
);
if (iResult
!= 0) {
printf("WSAStartup failed with error: %d\n", iResult
);
return 1;
}
ZeroMemory(&hints
, sizeof(hints
));
hints
.ai_family
= AF_INET
;
hints
.ai_socktype
= SOCK_STREAM
;
hints
.ai_protocol
= IPPROTO_TCP
;
hints
.ai_flags
= AI_PASSIVE
;
iResult
= getaddrinfo(NULL, DEFAULT_PORT
, &hints
, &result
);
if (iResult
!= 0) {
printf("getaddrinfo failed with error: %d\n", iResult
);
WSACleanup();
return 1;
}
ListenSocket
= socket(result
->ai_family
, result
->ai_socktype
, result
->ai_protocol
);
if (ListenSocket
== INVALID_SOCKET
) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result
);
WSACleanup();
return 1;
}
iResult
= bind(ListenSocket
, result
->ai_addr
, (int)result
->ai_addrlen
);
if (iResult
== SOCKET_ERROR
) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result
);
closesocket(ListenSocket
);
WSACleanup();
return 1;
}
freeaddrinfo(result
);
iResult
= listen(ListenSocket
, SOMAXCONN
);
if (iResult
== SOCKET_ERROR
) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket
);
WSACleanup();
return 1;
}
Print_SerIP();
printf("-----------------------------------\n\
服务器已启动,(0.0.0.0)正在监听...\n\
============================================\n");
int id
= 0;
while (true)
{
ClientSocket
= accept(ListenSocket
, NULL, NULL);
if (ClientSocket
== INVALID_SOCKET
) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket
);
WSACleanup();
return 1;
}
printf("\n>>>连接成功...[ok]\n");
struct sockaddr_in sa
;
int len
= sizeof(sa
);
if (!getpeername(ClientSocket
, (struct sockaddr
*) & sa
, &len
))
{
printf("Client Ip:%s ", inet_ntoa(sa
.sin_addr
));
printf("Client Port:%d \n\n", ntohs(sa
.sin_port
));
}
thread
task(task_connect
, ClientSocket
, sa
);
task
.detach();
}
closesocket(ListenSocket
);
WSACleanup();
return 0;
}
void task_connect(SOCKET ClientSocket
, struct sockaddr_in ip
)
{
int len
= sizeof(int);
int iResult
;
char recvbuf
[DEFAULT_BUFLEN
];
int recvbuflen
= DEFAULT_BUFLEN
;
while (1)
{
memset(recvbuf
, 0, recvbuflen
);
iResult
= recv(ClientSocket
, recvbuf
, recvbuflen
- 1, 0);
memcpy(&len
, recvbuf
, sizeof(int));
strcpy(recvbuf
, recvbuf
+ sizeof(int));
if (iResult
> 0)
{
printf("[%s:%d]:(%d)\t\b>> %s", inet_ntoa(ip
.sin_addr
), ntohs(ip
.sin_port
), len
, recvbuf
);
while (len
> iResult
)
{
len
-= iResult
;
memset(recvbuf
, 0, recvbuflen
);
iResult
= recv(ClientSocket
, recvbuf
, recvbuflen
- 1, 0);
printf_s("%s", recvbuf
);
}
printf("\n");
strcpy(recvbuf
, "ok!");
int iSendResult
= send(ClientSocket
, recvbuf
, (int)strlen(recvbuf
), 0);
if (iSendResult
== SOCKET_ERROR
) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket
);
WSACleanup();
}
printf("reply : (%d) ok! \n-----------------------\n", iSendResult
);
}
else if (iResult
== 0) {
printf("Client [%s]: Connection closing...\n", inet_ntoa(ip
.sin_addr
));
}
else {
printf("Client [%s]: recv failed with error: %d\n", inet_ntoa(ip
.sin_addr
), WSAGetLastError());
closesocket(ClientSocket
);
printf("Client [%s]: Connection closing...\n", inet_ntoa(ip
.sin_addr
));
return;
}
}
iResult
= shutdown(ClientSocket
, SD_SEND
);
if (iResult
== SOCKET_ERROR
) {
printf("Client [%s]: shutdown failed with error: %d\n", inet_ntoa(ip
.sin_addr
), WSAGetLastError());
closesocket(ClientSocket
);
printf("Client [%s]: Connection closing...\n", inet_ntoa(ip
.sin_addr
));
return;
}
closesocket(ClientSocket
);
}
void Print_SerIP()
{
char host
[255];
if (gethostname(host
, sizeof(host
)) == SOCKET_ERROR
)
{
printf("无法获取主机名\n");
}
else
{
printf("本机计算机名为:\t\b%s\n", host
);
}
struct hostent
* p
= gethostbyname(host
);
if (p
== 0)
{
printf("无法获取计算机主机名及IP");
}
else
{
printf("本地环回测试IP为:\t127.0.0.1\n");
for (int i
= 0; p
->h_addr_list
[i
] != 0; i
++)
{
struct in_addr in
;
memcpy(&in
, p
->h_addr_list
[i
], sizeof(struct in_addr
));
printf("第%d块网卡的IP为:\t\b%s\n", i
+ 1, inet_ntoa(in
));
}
}
}
客户端完整代码
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define DEFAULT_BUFLEN 1024
#define DEFAULT_PORT "27015"
#pragma warning(disable:4996)
int __cdecl
main(int argc
, char** argv
)
{
WSADATA wsaData
;
SOCKET ConnectSocket
= INVALID_SOCKET
;
struct addrinfo
* result
= NULL, * ptr
= NULL, hints
;
char sendbuf
[DEFAULT_BUFLEN
];
char recvbuf
[DEFAULT_BUFLEN
];
int iResult
;
int recvbuflen
= DEFAULT_BUFLEN
;
char servIP
[50] = "127.0.0.1";
iResult
= WSAStartup(MAKEWORD(2, 2), &wsaData
);
if (iResult
!= 0) {
printf("WSAStartup failed with error: %d\n", iResult
);
return 1;
}
ZeroMemory(&hints
, sizeof(hints
));
hints
.ai_family
= AF_UNSPEC
;
hints
.ai_socktype
= SOCK_STREAM
;
hints
.ai_protocol
= IPPROTO_TCP
;
while (true)
{
printf("请输入服务器域名/IP地址:\n>>>");
fflush(stdout);
rewind(stdin);
scanf_s("%s", servIP
, 49);
iResult
= getaddrinfo(servIP
, DEFAULT_PORT
, &hints
, &result
);
if (iResult
!= 0) {
printf("getaddrinfo failed with error: %d\n", iResult
);
fflush(stdout);
continue;
}
for (ptr
= result
; ptr
!= NULL; ptr
= ptr
->ai_next
) {
ConnectSocket
= socket(ptr
->ai_family
, ptr
->ai_socktype
,
ptr
->ai_protocol
);
if (ConnectSocket
== INVALID_SOCKET
) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
iResult
= connect(ConnectSocket
, ptr
->ai_addr
, (int)ptr
->ai_addrlen
);
if (iResult
== SOCKET_ERROR
) {
closesocket(ConnectSocket
);
ConnectSocket
= INVALID_SOCKET
;
continue;
}
break;
}
break;
}
freeaddrinfo(result
);
if (ConnectSocket
== INVALID_SOCKET
) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
printf(">>>连接到服务器(%s)...\n>>>连接成功...[ok]\n", servIP
);
struct sockaddr_in sa
;
int len
= sizeof(sa
);
if (!getsockname(ConnectSocket
, (struct sockaddr
*) & sa
, &len
))
{
printf("Client Ip:%s ", inet_ntoa(sa
.sin_addr
));
printf("Client Port:%d \n\n", ntohs(sa
.sin_port
));
}
printf("max send: %d bites\n", DEFAULT_BUFLEN
);
printf("====================================================\n");
char buff
[40] = "";
sprintf(buff
, "title client:[%s: %d]", inet_ntoa(sa
.sin_addr
), ntohs(sa
.sin_port
));
system(buff
);
bool flag
= true;
while (flag
)
{
printf("@[%s] send: >>> ", servIP
);
fflush(stdout);
rewind(stdin);
if (0 == scanf_s("%[^\n]", sendbuf
+ sizeof(int), DEFAULT_BUFLEN
- sizeof(int) - 1))
{
printf("\ninput error: 输入错误(tips:最多发送 %d 字节数据) \n", DEFAULT_BUFLEN
- sizeof(int) - 1);
continue;
}
int len
= strlen(sendbuf
+ sizeof(int)) + sizeof(int);
memcpy(sendbuf
, &len
, sizeof(int));
if (0 == strncmp(sendbuf
, "end", 3))
{
iResult
= shutdown(ConnectSocket
, SD_SEND
);
if (iResult
== SOCKET_ERROR
) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket
);
WSACleanup();
return 1;
}
flag
= false;
}
else
{
iResult
= send(ConnectSocket
, sendbuf
, len
, 0);
if (iResult
== SOCKET_ERROR
) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket
);
WSACleanup();
return 1;
}
printf("|<--- (Sent size: %ld)\n|-------------------- \n", len
);
}
iResult
= recv(ConnectSocket
, recvbuf
, recvbuflen
, 0);
if (iResult
> 0)
printf("|---> (recv size: %d ) \n\n", iResult
);
else if (iResult
== 0)
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
}
closesocket(ConnectSocket
);
WSACleanup();
return 0;
}
服务器/客户端运行效果: