编译环境:DEV C++
配置编译器
Windows 下 实现 Socket 编译需要 ws2_32.lib 这个库的支撑,所以我们编译前应该配置下编译器,具体配置步骤如下:
Tools -> Compiler Options
加入 -l 链接,如图所示:
实现的功能
服务器端与客户端可以互相自由给对方发送消息,无需在意接收与发送的顺序(利用线程实现)!可以实现加法运算。如需其它的功能,可以自行补充,如:实现四则运算、文件传输等。
服务器程序
/*
Name: TCP Server
Copyright: -lws2_32
Author: Lance#
Date: 18/05/18
Description: TCP Server
*/
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <string.h>
#define PORT 8080
#define BUFSIZE 1024
/* 客户端Socket与发送缓冲 */
SOCKET client;
unsigned char SendBuf[BUFSIZE+1];
enum{
NoConnection,
Connected,
}LinkStatus;
/* 客户端连接状态监控线程 */
DWORD WINAPI print_message(LPVOID arg)
{
while(1){
if(!LinkStatus){
printf(" 等待客户端连接 .... \\r\\n");
sleep(1);
}
}
}
/* 服务器发送消息线程 */
DWORD WINAPI send_message(LPVOID arg)
{
while(1){
memset(SendBuf, 0, 1024);
fgets(SendBuf, 1024, stdin);
send(client, SendBuf, 1024, 0);
}
}
int main(int argc, char* argv[])
{
WSADATA wsaData;
struct sockaddr_in sin_addr;
struct sockaddr_in remoteAddr;
unsigned char recvData[BUFSIZE+1];
int nAddrlen = sizeof(remoteAddr);
unsigned int num_l, num_r;
unsigned char sum_buf[100] = {0};
/* 线程标识 */
HANDLE pthread;
/* 启动 WSA */
WORD sockVersion = MAKEWORD(2, 2);
if (WSAStartup(sockVersion, &wsaData)){
perror("WSA boot failed!");
return -1;
}
/* 创建服务端套接字 */
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server == INVALID_SOCKET){
perror("socket error!");
return -1;
}
/* 配置 sin_addr */
sin_addr.sin_family = AF_INET;
sin_addr.sin_port = htons(PORT);
/* 可监听任意的地址 */
sin_addr.sin_addr.S_un.S_addr = INADDR_ANY;
/* 监听指定的地址 */
// sin_addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.149");
/* 绑定 */
if (bind(server, (LPSOCKADDR)&sin_addr, sizeof(sin_addr)) == SOCKET_ERROR){
perror("bind error!");
return -1;
}
/* 监听 */
if (listen(server, 100) == SOCKET_ERROR){
perror("listen error!");
return -1;
}
puts("服务器成功启动");
/* 创建状态线程 */
CreateThread(NULL,0,print_message,NULL,0,NULL);
/* 创建消息线程 */
pthread = CreateThread(NULL,0,send_message,NULL,0,NULL);
while (1)
{
LinkStatus = NoConnection;
client = accept(server, (SOCKADDR *)&remoteAddr, &nAddrlen);
LinkStatus = Connected;
if (client == INVALID_SOCKET)
{
perror("accept error!");
continue;
}
printf("客户端:%s 已连接\\r\\n", inet_ntoa(remoteAddr.sin_addr));
while(1){
/* 数据接收 */
memset(recvData, 0, sizeof(recvData));
int ret = recv(client, recvData, 1024, 0);
if (ret > 0){
printf("Recv: %s", recvData);
/* 实现加法运算,客户端发来 "%d + %d =" 形式的数据后,将结果返回至客户端 */
if(sscanf(recvData, "%d + %d =", &num_l, &num_r) == 2){
sprintf(sum_buf, "%d + %d ,sum is %d", num_l, num_r, num_l + num_r);
send(client, sum_buf, sizeof(sum_buf), 0);
memset(sum_buf, 0, sizeof(sum_buf));
}
}else
/* 客户端异常则断开当前连接 */
goto Reconnect;
/* 客户端要求退出的话则断开当前连接 */
if(!strncmp(recvData, "quit", 4))
goto Reconnect;
}
Reconnect:
closesocket(client);
puts("*** 客户端已断开");
}
/* 关闭服务器套接字 */
closesocket(server);
WSACleanup();
return 0;
}
客户端程序
/*
Name: TCP Client
Copyright: -lws2_32
Author: Lance#
Date: 18/05/18
Description: TCP Client
*/
#include <stdio.h>
#include <winsock2.h>
#include <Windows.h>
#include <string.h>
#define PORT 8080
#define BUFSIZE 1024
unsigned char recvData[BUFSIZE+1] = {0};
/* 线程标识 */
HANDLE pthread;
DWORD WINAPI recv_message(LPVOID arg)
{
int res;
while(1){
memset(recvData, 0, 1024);
res = recv((SOCKET)arg, recvData, 1024, 0);
if(res > 0)
printf("Recv: %s", recvData);
else{
printf("*** 服务器已退出(回车退出程序)");
return 0;
}
}
}
int main(int argc, char * argv[])
{
unsigned char SendBuf[BUFSIZE+1] = {0};
WSADATA wsaData;
SOCKADDR_IN addrServ;
if(argc != 2){
puts("argc error");
puts("Usage: <client.exe> <ip addr>");
return -1;
}
/* 启动 WSA */
WORD sockVersion = MAKEWORD(2, 2);
if (WSAStartup(sockVersion, &wsaData)){
perror("WSA boot failed!");
return -1;
}
/* 创建 socket */
SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client == INVALID_SOCKET){
perror("socket failed");
return -1;
}
/* 配置 socket */
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(PORT);
/* 配置服务器 IP */
addrServ.sin_addr.S_un.S_addr = inet_addr(argv[1]);
/* 连接至服务器 */
int ret = connect(client,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
if (SOCKET_ERROR == ret){
perror("socket connect failed");
closesocket(client);
WSACleanup();
return -1;
}
/* 创建工作线程 */
pthread = CreateThread(NULL,0 ,recv_message,(LPVOID)client,0,NULL);
puts("客户端成功启动,输入\'quit\'关闭客户端");
while(1)
{
memset(SendBuf,0,sizeof(SendBuf));
fgets(SendBuf, 1024, stdin);
ret = send(client, SendBuf, 1024, 0);
if (SOCKET_ERROR == ret){
closesocket(client);
exit(0);
}
/* 客户端退出 */
if(!strncmp(SendBuf, "quit", 4))
goto Disconnect;
}
Disconnect:
closesocket(client);
WSACleanup();
return 0;
}
运行结果演示
打开 CMD,进入可执行文件所在目录
执行 server.exe 运行服务器;
启动另一个 CMD,执行 client.exe 127.0.0.1 运行客户端。
双方可进行通信,效果如图: