参考资料: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$/记搜

    \(Des\) 给定一个有向图,起点为\(1\),终点为\(n\),求和最短路相差不超过\(k\)的路径数量.有\(0\)边.如果有无数条,则输出\(-1\). \(n\leq 10^5,k\leq ...

  2. 01_console 你真的了解吗,不曾了解过得console~

    对于 console 你只知道 console.log 吗? 那你就 out 啦!!! // 1. 显示信息 console.log('hello'); console.info('信息'); con ...

  3. 从零开始Go语言-GoLand(编译器)-Windows(平台)

    本文章适合那些想入门Go语言,却又不知道如何搭建自己的第一个HelloWorld的同学. 推荐几个Go语言相关学习网站: C语言中文网: http://c.biancheng.net/golang/ ...

  4. rabbitmq系列(一)初识rabbitmq

    为什么要使用消息中间件 案例:假如我们开发了一个商品抢购网站.这个网站的目的就是在某一时间点进行抢购商品,同时要求用户注册,在注册的时候会同时给用户电话和邮箱中发送验证码,以便完成信息注册.传统做法应 ...

  5. 记录一下第一次用markdown写博客回滚过程

    前面写博客,一直用的是博客园的TinyMCE编辑器, 今天不知道哪根筋搭牢了,想试试用Markdown写. 于是在“选项”里面把默认编辑器修改为“Markdown”,鉴于本人有一定的Markdown基 ...

  6. JPQ整合Querydsl入门篇

    # JPQ整合Querydsl入门篇  不知道你们喜不喜欢用JPA ,我本人是很喜欢 不要和我说JPA不适合复杂查询等等的,你要知道现在都是微服务,只要你服务器拆分够细表设计够合理,都是服务之间调能用 ...

  7. Office系列(2)---提取Office文件(Word、PPT)中的所有图片

    回顾一下上文结尾的问题:如何给文档设置一个合适的封面图?其中一个解决方案就是,获取Office文件内部的图片作为封面.这里就详细介绍下获取图片的几种方式,以及他们各自的优缺点. PS:因为之前用VST ...

  8. scrapy基本的流程 糗事百科

    https://www.cnblogs.com/c-x-a/p/9889623.html 创建scrapy工程 1.scrapy startproject xxx xxx就是你的项目名,这里我们给我们 ...

  9. mysql 添加/删除列(column)

    1.添加 格式:alter table 表名 add column 列名 列的数据类型;示例alter table test4 add column addr text; 2.删除 格式: alter ...

  10. PHP——常量

    一.什么是常量 常量可以理解为值不变的量(如圆周率)或者是常量值被定义后,在脚本的其他任何地方都不可以被改变.PHP中的常量分为自定义常量和系统常量,自定义常量是根据我们开发的需要,而定义的常量,它通 ...