编译环境: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 运行客户端。

双方可进行通信,效果如图:

完美实现 Windows 下网络通信的更多相关文章

  1. 虚拟机+桥接模式+Host-only模式 搭建完美的Windows下Linux开发环境

    相信有很多鞋童和我一个样是一枚Linux码农(我现在还是嵌入式方向). 做Linux开发势必需要一个Linux环境, 大多数开发者会首先选择一个Linux发行版, 其中Ubuntu LTS版本应该是选 ...

  2. 在windows下完美安装GitHub

    笔者最近在Windows下安装GitHub,过程中遇到不少问题.现在把安装的详细步骤分享给大家,免得大家走弯路. 笔者安装了GitHub for Windows程序,一切都运行顺利.但事情没有结束,首 ...

  3. 在Windows下使用Git

    关于Git git是当今最流行的版本控制系统,因为是诞生在Linux操作系统下,因此Linux对git天生有最好的支持,但好在各路大牛的努力下,目前在Windows也能较为完美的使用.以下便是我使用g ...

  4. Windows下 VM12虚拟机安装OS X 10.11 和VM TOOLS

    Windows下虚拟机安装Mac OS X —– VMware Workstation12安装Mac OS X 10.11 本文即将介绍WIN虚拟MAC的教程.完整详细教程(包含安装中的一些问题) [ ...

  5. Windows 下 pdf2word 的可用软件记录

    因为用 latex 写的原稿,提交审阅的时候有 Word 版本的要求,只好找软件来转换.折腾了一整天的 Linux 下latex2html, latex2rtf 等两个曲线救国的方式来生成 Word ...

  6. Atom编辑器在windows下怎么更改安装路径

    作为一个有良(mei)知(qian)的程序员,也不能老是用和谐版的source insight. 而且source insight也不是十分的完美,本身有一些缺陷. 比如说中文的支持,比如说反应很慢的 ...

  7. Android拓展系列(11)--打造Windows下便携的Android源码阅读环境

    因为EXT和NTFS格式的差异,我一直对于windows下阅读Android源码感到不满. 前几天,想把最新的android5.0的源码下下来研究一下,而平时日常使用的又是windows环境,于是专门 ...

  8. winsock教程- windows下的socket编程(c语言实现)

    winsock教程- windows下的socket编程(c语言实现) 使用winsock进行socket 编程     这是一个学习windows下socket编程(c语言)的快速指南.这是因为一下 ...

  9. 在Windows下编写并运行第一个ASP.NET 5 Preview Web API程序

    2015年07月21日在微软中国MSDN的官方微博上得知Visual Studio 2015正式版完美发布. 抱着尝鲜的心态下载了Visual Studio社区版本. 在这个首发的版本里面,我们可以看 ...

随机推荐

  1. 2019浙大校赛--G--Postman(简单思维题)

    一个思维水题 题目大意为,一个邮递员要投递N封信,一次从邮局来回只能投递K封.求最短的投递总距离.需注意,最后一次投递后无需返回邮局. 本题思路要点: 1.最后一次投递无需返回邮局,故最后一次投递所行 ...

  2. U-Boot bootargs简析

    Linux内核启动时需要一些配置信息,如根文件系统的类型.flash分区情况.串口终端的编号.内存的使用情况等等,而由于U-Boot和Linux Kernel的镜像是独立的两个文件,所以只能两者约定好 ...

  3. Forward团队-爬虫豆瓣top250项目-项目总结

    托管平台地址:https://github.com/xyhcq/top250 小组名称:Forward团队 组长:马壮 成员:李志宇.刘子轩.年光宇.邢云淇.张良 我们这次团队项目内容是爬取豆瓣电影T ...

  4. Linux启动流程和脚本服务-6

    授课笔记:----------------------------------- linux系统启动流程:一.初始化阶段:1.grub引导界面2.识别硬件3.初始化驱动 二.加载/etc/rc.d/r ...

  5. JSTL配置文件下载地址

    Apache Tomcat安装JSTL 库步骤如下: 从Apache的标准标签库中下载的二进包(jakarta-taglibs-standard-current.zip). 官方下载地址:http:/ ...

  6. unigui+fastreport报表打印

    unigui+fastreport报表打印   unigui+fastreport报表打印 FASTREPORT导出成PDF报表,UNIGUI的TUniURLFrame显示PDF报表并打印. func ...

  7. Javascript高级编程学习笔记(18)—— 引用类型(7)单体内置对象

    什么是内置对象呢? js高级程序设计中给出的定义为:由ES规定不依赖于宿主环境的对象,这些对象在JS执行前就已经存在 前面我们介绍的引用类型都是内置对象 除了这些对象外ECMA还规定了两个单体内置对象 ...

  8. Java变量与运算

    变量 1.变量名可以使用 数字.字母.下划线.$符号.数字包括 '0'~'9' 和某种语言中表示数字的任何 Unicode 字符.字母包括 'A'~'Z'.'a'~'z' 和某种语言中表示字母的任何 ...

  9. 一条SQL语句在MySQL中如何执行的

    本篇文章会分析一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的. 在分析之前我会先带着你看看 MySQL 的基础架构, ...

  10. 关于DB Link

    概述 DB Link是一个定义了本地数据库到远程数据库路径的对象,是schema object,它是单向连接 通过DB Link可查询remote数据库的对象及运行其程序 在分布式环境里,DB Lin ...