参考资料:http://c.biancheng.net/cpp/socket/

http://www.winsocketdotnetworkprogramming.com/

socket 是“套接字”意思,是计算机之间进行通信的一种约定。

通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。

学习 socket,也就是学习计算机之间如何通信,并编写出实用的程序。

WD--返回WinSock的实现信息。

WD是一个WSAData结构:

typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
#ifdef _WIN64
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
#else
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
#endif
} WSADATA, FAR * LPWSADATA;

最简单的WinSocket程序

server.c

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 1024 int main()
{
WSADATA wsaData; //包含系统所支持的WinSocket版本信息
SOCKET sServer; //服务器Socket,用于监听客户端请求
SOCKET sClient; //客户端Socket,用于实现与客户端的通信
int retVal; //调用各种Socket函数的返回值
char buf[BUFFER_SIZE]; //用于接受客户端数据的缓冲区 //初始化WinSocket 2.2
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("WSAStartup failed!\n");
return -1;
} /**
* 打印socket信息
* 低位字节存储主版本号,高位字节存储副版本号
*/
printf("[wVersion] = %d.%d\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
printf("[wHighVersion] = %d.%d\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
printf("[szDescription] = %s\n", wsaData.szDescription);
printf("[szSystemStatus] = %s\n", wsaData.szSystemStatus);
printf("[iMaxSockets] = %d\n", wsaData.iMaxSockets);
printf("[iMaxUdpDg] = %d\n", wsaData.iMaxUdpDg); //创建用于监听的socket
sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sServer == INVALID_SOCKET)
{
printf("socket failed!\n");
WSACleanup();
return -1;
} /**
* 设置服务器socket地址
* 服务器监听地址为INADDR_ANY-->在任意本地地址(0.0.0.0)监听
* 监听端口号为9999
*/
SOCKADDR_IN addrServ;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(9999);
addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //绑定Sockets Server到本地地址
retVal = bind(sServer, (const struct sockaddr*)&addrServ, sizeof(SOCKADDR_IN));
if (retVal == SOCKET_ERROR)
{
printf("bind failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
} //在Sockets Server上进行监听
retVal = listen(sServer, 1);
if (retVal == SOCKET_ERROR)
{
printf("listen failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
} //接受来自客户端的请求
printf("TCP Server start...\n");
struct sockaddr_in addrClient;
int addrClientlen = sizeof(addrClient);
sClient = accept(sServer, (struct sockaddr FAR *)&addrClient, &addrClientlen);
if (sClient == INVALID_SOCKET)
{
printf("accept failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
} //printf("%s\n", inet_ntoa(addrClient.sin_addr)); while (1)
{
//清空接收数据的缓冲区
memset(buf, 0, sizeof(buf));
retVal = recv(sClient, buf, BUFFER_SIZE, 0);
if (retVal == SOCKET_ERROR)
{
printf("recv failed\n");
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return -1;
}
SYSTEMTIME st;
GetLocalTime(&st);
char szDateTime[50];
sprintf(szDateTime, "%4d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond); //打印输出信息
printf("%s, Recv From Client [%s:%d] :%s\n", szDateTime, inet_ntoa(addrClient.sin_addr), addrClient.sin_port, buf); if (strcmp(buf, "quit") == 0)
{
send(sClient, "quit", strlen("quit"), 0);
break;
}
else
{
char msg[BUFFER_SIZE];
sprintf(msg, "Message received - %s", buf);
retVal = send(sClient, msg, strlen(msg), 0);
if (retVal == SOCKET_ERROR)
{
printf("send failed\n");
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return -1;
}
}
} //清除工作
closesocket(sServer);
closesocket(sClient);
WSACleanup(); return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 1024 int main()
{
WSADATA wsaData;
SOCKET sHost;
int retVal;
char buf[BUFFER_SIZE]; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("WSAStartup failed!\n");
return -1;
} sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sHost == INVALID_SOCKET)
{
printf("socket failed!\n");
WSACleanup();
return -1;
} SOCKADDR_IN addrServ;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(9999);
addrServ.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); retVal = connect(sHost, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
if (retVal == SOCKET_ERROR)
{
printf("connect failed!\n");
closesocket(sHost);
WSACleanup();
return -1;
} while (1)
{
printf("Please input a string:");
gets(buf);
retVal = send(sHost, buf, strlen(buf), 0);
if (retVal == SOCKET_ERROR)
{
printf("send failed!\n");
closesocket(sHost);
WSACleanup();
return -1;
}
memset(buf, 0, sizeof(buf));
retVal = recv(sHost, buf, sizeof(buf), 0);
if (retVal == SOCKET_ERROR)
{
printf("recv failed!\n");
closesocket(sHost);
WSACleanup();
return -1;
}
printf("Recv From Server: %s\n", buf);
if(strcmp(buf, "quit") == 0)
{
break;
}
} //วๅณนคื๗
closesocket(sHost);
WSACleanup(); return 0;
}

对于完成的client/server程序可以使用NC来测试

1)连接到 remote 主机,例子:

格式:nc -nvv 192.168.x.x 80

讲解:连到192.168.x.x的TCP80端口



2)监听 local 主机,例子:

格式:nc -l -p 80

讲解:监听本机的TCP80端口

winsocket入门学习的更多相关文章

  1. vue入门学习(基础篇)

    vue入门学习总结: vue的一个组件包括三部分:template.style.script. vue的数据在data中定义使用. 数据渲染指令:v-text.v-html.{{}}. 隐藏未编译的标 ...

  2. Hadoop入门学习笔记---part4

    紧接着<Hadoop入门学习笔记---part3>中的继续了解如何用java在程序中操作HDFS. 众所周知,对文件的操作无非是创建,查看,下载,删除.下面我们就开始应用java程序进行操 ...

  3. Hadoop入门学习笔记---part3

    2015年元旦,好好学习,天天向上.良好的开端是成功的一半,任何学习都不能中断,只有坚持才会出结果.继续学习Hadoop.冰冻三尺,非一日之寒! 经过Hadoop的伪分布集群环境的搭建,基本对Hado ...

  4. PyQt4入门学习笔记(三)

    # PyQt4入门学习笔记(三) PyQt4内的布局 布局方式是我们控制我们的GUI页面内各个控件的排放位置的.我们可以通过两种基本方式来控制: 1.绝对位置 2.layout类 绝对位置 这种方式要 ...

  5. PyQt4入门学习笔记(一)

    PyQt4入门学习笔记(一) 一直没有找到什么好的pyqt4的教程,偶然在google上搜到一篇不错的入门文档,翻译过来,留以后再复习. 原始链接如下: http://zetcode.com/gui/ ...

  6. Hadoop入门学习笔记---part2

    在<Hadoop入门学习笔记---part1>中感觉自己虽然总结的比较详细,但是始终感觉有点凌乱.不够系统化,不够简洁.经过自己的推敲和总结,现在在此处概括性的总结一下,认为在准备搭建ha ...

  7. Retrofit 入门学习

    Retrofit 入门学习官方RetrofitAPI 官方的一个例子 public interface GitHubService { @GET("users/{user}/repos&qu ...

  8. MyBatis入门学习教程-使用MyBatis对表执行CRUD操作

    上一篇MyBatis学习总结(一)--MyBatis快速入门中我们讲了如何使用Mybatis查询users表中的数据,算是对MyBatis有一个初步的入门了,今天讲解一下如何使用MyBatis对use ...

  9. opengl入门学习

    OpenGL入门学习 说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640 ...

随机推荐

  1. $[NOIp2017]$ 宝藏 状压$dp$

    \(Sol\) 觉得这里是个很巧妙的地方吖,就是记下当前扩展点集的最大深度,然后强制下一步扩展的点集都是最大深度+1.这样做在当前看可能会导致误算答案导致答案偏大,但是整个\(dp\)完成后一定可以得 ...

  2. linux MySQL 5.7+keepalived 主备服务器自主切换

    一.环境准备1.关闭防火墙与selinux systemctl stop firewalld setenforce 0 sed -i 's/SELINUX=.*/SELINUX=disabled/g' ...

  3. 1024 科学计数法 (20 分)C与Java

    科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式 [±][1-9].[0-9]+E[±][0-9]+,即数字的整数部分只有 1 位,小数部分至少有 1 位,该数字及其指数部 ...

  4. Java截图小程序源码

    Java编写的全屏截图小程序 package cnom.test.testUtils; import java.awt.AWTException; import java.awt.Dimension; ...

  5. 【转】面向GC的Java编程

    Java程序员在编码过程中通常不需要考虑内存问题,JVM经过高度优化的GC机制大部分情况下都能够很好地处理堆(Heap)的清理问题.以至于许多Java程序员认为,我只需要关心何时创建对象,而回收对象, ...

  6. python循环语句(while和for)

    循环语句分成两种,while循环 和 for循环 作用:可以使指定的代码块重复指定的次数 while循环: # 语法: # while 条件表达式 : # 代码块 # else : # 代码块 # 执 ...

  7. Eureka 主动下线服务

    原因: 测试环境由于机器换ip,神奇的出现了更新之前,之后的IP同时在Eureka上注册了. 方法一:直接停掉服务 默认情况下,如果Eureka Server在90秒没有收到Eureka客户的续约,它 ...

  8. 贪心 + DFS

    A New Year party is not a New Year party without lemonade! As usual, you are expecting a lot of gues ...

  9. 算法笔记codeup-Contest100000568

    A #include <stdio.h> int main() { ; ; while(a) { sum=sum+a; a--; } printf("%d",sum); ...

  10. 公文流转系统v0.1

    河北金力集团公文流转系统 1.项目需求: 河北金力集团是我省机械加工的龙头企业,主要从事矿山机械制造及各种机械零部件加工.企业有3个厂区,主厂区位于省高新技术开发区,3个分厂分别在保定.邢台和唐山.为 ...