C语言WinSock学习笔记第1/2页

作者:肖进

Socket(套接字)

◆先看定义:
typedef unsigned int u_int;
typedef u_int SOCKET;
◆Socket相当于进行网络通信两端的插座,只要对方的Socket和自己的Socket有通信联接,双方就可以发送和接收数据了。其定义类似于文件句柄的定义。

◆Socket有五种不同的类型:

1、流式套接字(stream socket)
定义:
#define SOCK_STREAM 1 
流式套接字提供了双向、有序的、无重复的以及无记录边界的数据流服务,适合处理大量数据。它是面向联结的,必须建立数据传输链路,同时还必须对传输的数据进行验证,确保数据的准确性。因此,系统开销较大。

2、 数据报套接字(datagram socket)

定义:
#define SOCK_DGRAM 2 
数据报套接字也支持双向的数据流,但不保证传输数据的准确性,但保留了记录边界。由于数据报套接字是无联接的,例如广播时的联接,所以并不保证接收端是否正在侦听。数据报套接字传输效率比较高。

3、原始套接字(raw-protocol interface)

定义:
#define SOCK_RAW 3 
原始套接字保存了数据包中的完整IP头,前面两种套接字只能收到用户数据。因此可以通过原始套接字对数据进行分析。
其它两种套接字不常用,这里就不介绍了。

◆Socket开发所必须需要的文件(以WinSock V2.0为例):

头文件:Winsock2.h

库文件:WS2_32.LIB

动态库:W32_32.DLL

一些重要的定义

1、数据类型的基本定义:这个大家一看就懂。
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
2、 网络地址的数据结构,有一个老的和一个新的的,请大家留意,如果想知道为什么,
请发邮件给Bill Gate。其实就是计算机的IP地址,不过一般不用用点分开的IP地
址,当然也提供一些转换函数。

◆ 旧的网络地址结构的定义,为一个4字节的联合:
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
#define s_addr S_un.S_addr /* can be used for most tcp & ip code */
//下面几行省略,反正没什么用处。
};
其实完全不用这么麻烦,请看下面:

◆ 新的网络地址结构的定义:
非常简单,就是一个无符号长整数 unsigned long。举个例子:IP地址为127.0.0.1的网络地址是什么呢?请看定义:
#define INADDR_LOOPBACK 0x7f000001
3、 套接字地址结构

(1)、sockaddr结构:
struct sockaddr {
u_short sa_family; /* address family */
char sa_data[14]; /* up to 14 bytes of direct address */
};
sa_family为网络地址类型,一般为AF_INET,表示该socket在Internet域中进行通信,该地址结构随选择的协议的不同而变化,因此一般情况下另一个与该地址结构大小相同的sockaddr_in结构更为常用,sockaddr_in结构用来标识TCP/IP协议下的地址。换句话说,这个结构是通用socket地址结构,而下面的sockaddr_in是专门针对Internet域的socket地址结构。

(2)、sockaddr_in结构
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin _family为网络地址类型,必须设定为AF_INET。sin_port为服务端口,注意不要使用已固定的服务端口,如HTTP的端口80等。如果端口设置为0,则系统会自动分配一个唯一端口。sin_addr为一个unsigned long的IP地址。sin_zero为填充字段,纯粹用来保证结构的大小。

◆ 将常用的用点分开的IP地址转换为unsigned long类型的IP地址的函数:
unsigned long inet_addr(const char FAR * cp )
用法:
unsigned long addr=inet_addr("192.1.8.84")
◆ 如果将sin_addr设置为INADDR_ANY,则表示所有的IP地址,也即所有的计算机。
#define INADDR_ANY (u_long)0x00000000
4、 主机地址:

先看定义:
struct hostent {
char FAR * h_name; /* official name of host */
char FAR * FAR * h_aliases; /* alias list */
short h_addrtype; /* host address type */
short h_length; /* length of address */
char FAR * FAR * h_addr_list; /* list of addresses */
#define h_addr h_addr_list[0] /* address, for backward compat */
};
h_name为主机名字。
h_aliases为主机别名列表。
h_addrtype为地址类型。
h_length为地址类型。
h_addr_list为IP地址,如果该主机有多个网卡,就包括地址的列表。
另外还有几个类似的结构,这里就不一一介绍了。

5、 常见TCP/IP协议的定义:
#define IPPROTO_IP 0 
#define IPPROTO_ICMP 1 
#define IPPROTO_IGMP 2 
#define IPPROTO_TCP 6 
#define IPPROTO_UDP 17 
#define IPPROTO_RAW 255 
具体是什么协议,大家一看就知道了。

套接字的属性

为了灵活使用套接字,我们可以对它的属性进行设定。

1、 属性内容:
//允许调试输出
#define SO_DEBUG 0x0001 /* turn on debugging info recording */
//是否监听模式
#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
//套接字与其他套接字的地址绑定
#define SO_REUSEADDR 0x0004 /* allow local address reuse */
//保持连接
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
//不要路由出去
#define SO_DONTROUTE 0x0010 /* just use interface addresses */
//设置为广播
#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
//使用环回不通过硬件
#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
//当前拖延值
#define SO_LINGER 0x0080 /* linger on close if data present */
//是否加入带外数据
#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
//禁用LINGER选项
#define SO_DONTLINGER (int)(~SO_LINGER)
//发送缓冲区长度
#define SO_SNDBUF 0x1001 /* send buffer size */
//接收缓冲区长度
#define SO_RCVBUF 0x1002 /* receive buffer size */
//发送超时时间
#define SO_SNDTIMEO 0x1005 /* send timeout */
//接收超时时间
#define SO_RCVTIMEO 0x1006 /* receive timeout */
//错误状态
#define SO_ERROR 0x1007 /* get error status and clear */
//套接字类型
#define SO_TYPE 0x1008 /* get socket type */
2、 读取socket属性:
int getsockopt(SOCKET s, int level, int optname, char FAR * optval, int FAR * optlen)
s为欲读取属性的套接字。level为套接字选项的级别,大多数是特定协议和套接字专有的。如IP协议应为 IPPROTO_IP。
optname为读取选项的名称
optval为存放选项值的缓冲区指针。
optlen为缓冲区的长度
用法:
int ttl=0; //读取TTL值
int rc = getsockopt( s, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl));
//来自MS platform SDK 2003
3、 设置socket属性:
int setsockopt(SOCKET s,int level, int optname,const char FAR * optval, int optlen)
s为欲设置属性的套接字。
level为套接字选项的级别,用法同上。
optname为设置选项的名称
optval为存放选项值的缓冲区指针。
optlen为缓冲区的长度

用法:
int ttl=32; //设置TTL值
int rc = setsockopt( s, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl));
套接字的使用步骤

1、启动Winsock:对Winsock DLL进行初始化,协商Winsock的版本支持并分配必要的
资源。(服务器端和客户端)
int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData )

wVersionRequested为打算加载Winsock的版本,一般如下设置:
wVersionRequested=MAKEWORD(2,0)
或者直接赋值:wVersionRequested=2

LPWSADATA为初始化Socket后加载的版本的信息,定义如下:
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
} WSADATA, FAR * LPWSADATA;
如果加载成功后数据为:
wVersion=2表示加载版本为2.0。
wHighVersion=514表示当前系统支持socket最高版本为2.2。
szDescription="WinSock 2.0"
szSystemStatus="Running"表示正在运行。
iMaxSockets=0表示同时打开的socket最大数,为0表示没有限制。
iMaxUdpDg=0表示同时打开的数据报最大数,为0表示没有限制。
lpVendorInfo没有使用,为厂商指定信息预留。
该函数使用方法:
WORD wVersion=MAKEWORD(2,0);
WSADATA wsData;
int nResult= WSAStartup(wVersion,&wsData);
if(nResult !=0)
{
//错误处理
}
2、创建套接字:(服务器端和客户端)
SOCKET socket( int af, int type, int protocol );
af为网络地址类型,一般为AF_INET,表示在Internet域中使用。
type为套接字类型,前面已经介绍了。
protocol为指定网络协议,一般为IPPROTO_IP。
用法:
SOCKET sock=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
if(sock==INVALID_SOCKET)
{
//错误处理
}
3、套接字的绑定:将本地地址绑定到所创建的套接字上。(服务器端和客户端)
int bind( SOCKET s, const struct sockaddr FAR * name, int namelen )
s为已经创建的套接字。
name为socket地址结构,为sockaddr结构,如前面讨论的,我们一般使用sockaddr_in
结构,在使用再强制转换为sockaddr结构。
namelen为地址结构的长度。
用法:
sockaddr_in addr;
addr. sin_family=AF_INET;
addr. sin_port= htons(0); //保证字节顺序
addr. sin_addr.s_addr= inet_addr("192.1.8.84")
int nResult=bind(s,(sockaddr*)&addr,sizeof(sockaddr));
if(nResult==SOCKET_ERROR)
{
//错误处理
}
4、 套接字的监听:(服务器端)
int listen(SOCKET s, int backlog )
s为一个已绑定但未联接的套接字。
backlog为指定正在等待联接的最大队列长度,这个参数非常重要,因为服务器一般可
以提供多个连接。
用法:
int nResult=listen(s,5) //最多5个连接
if(nResult==SOCKET_ERROR)
{
//错误处理
}
5、套接字等待连接::(服务器端)
SOCKET accept( SOCKET s, struct sockaddr FAR * addr, int FAR * addrlen )
s为处于监听模式的套接字。
sockaddr为接收成功后返回客户端的网络地址。
addrlen为网络地址的长度。

用法:
sockaddr_in addr;
SOCKET s_d=accept(s,(sockaddr*)&addr,sizeof(sockaddr));
if(s==INVALID_SOCKET)
{
//错误处理
}

当前1/2页 12下一页阅读全文

(0)

相关推荐

  • C语言编程中函数的基本学习教程

    C 语言中的函数等价于 Fortran 语言中的子程序或函数,也等价于 Pascal 语言中的过程或函数.函数为计算的封装提供了一种简便的方法,此后使用函数时不需要考虑它是如何实现的.使用设计正确的函数,程序员无需考虑功能是如何实现的,而只需知道它具有哪些功能就够了.在 C 语言中可以简单.方便.高效地使用函数.我们经常会看到在定义后仅调用了一次的短函数,这样做可以使代码段更清晰易读. 到目前为止,我们所使用的函数(如 printf.getchar 和 putchar 等)都是函数库中提供的函数

  • 快速入门的一些C\C++书籍

    人们常常问我有什么C++和编程的书籍推荐,今天就为大家分享了几本 第一个注意项:如果你打算学习C++,请务必学习最新版的C++ 2011.这个版本的C++移除了许多由C++强大带来的一些痛苦之处.另外,也不用担心C++ 2014的书籍,大多数编译器已经开始支持它了. 学习编程 学习编程包含以下几个重要方面: 了解语言的语法 知道那些特性可以使用和何时使用 写出可读性好的代码:编译器可以理解,但是下一个人是否可以阅读呢? 在一个更高层次设计结构良好的程序 为了学习一门语言,通常我们可以找到叫<X语

  • C语言入门之指针用法教程

    本文针对C语言初学者详细讲述了指针的用法,并配以实例进行说明.具体分析如下: 对于C语言初学者来说,需要明白指针是啥?重点就在一个"指"上.指啥?指的地址.啥地址?内存的地址. 上面说明就是指针的本质了. 这里再详细解释下.数据存起来是要存在内存里面的,就是在内存里圈出一块地,在这块地里放想放的东西.变量关心的是这块地里放的东西,并不关心它在内存的哪里圈的地:而指针则关心这块地在内存的哪个地方,并不关心这块地多大,里面存了什么东西. 指针怎么用呢?下面就是基本用法: int a, b,

  • 为什么要学习C语言 C语言优势分析

    不止一个学生问到我:"老师,为什么我们的应用程序设计要学C语言而不是别的?C语言不是已经过时了吗?如果现在要写一个Windows程序,用VB或Dephi开发多快呀,用C行吗?退一万步,为什么选择C而不是C++呢?" 这个问题三言两语还真说不全.简单来说,C语言是计算机程序语言的基础,是实用的程序设计工具,学好C语言对你今后学习JAVA.C++.VB等可以打下良好的基础,因为这些语言大部分都是由C语言扩充或衍生而来的.C可以用于开发比较底层的东西,比如驱动.通信协议之类,在Unix和Li

  • C语言指针学习经验总结浅谈

    这篇C语言指针学习经验总结主要是我入职以来学习C指针过程中的点滴记录.文档里面就不重复书上说得很清楚的概念性东西,只把一些说得不清楚或理解起来比较费解的东西做一下讲解,希望能达到以下三个目的 1.通过写这些东西,把我脑袋中关于C的模糊的知识清晰化.2.给初转C的同事们一点提示和帮助.3.也希望各位前辈检查一下文档中是否有理解偏差的地方.1 指针的概念分解      指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址. 要搞清一个指针需要搞清指针的四方面的内容: 1.指针的类型2.指

  • JavaScript入门学习书籍推荐

    在 JavaScript 方面,自己不是什么专家,也不是什么高手,但自己一路走来,JavaScript 从迷茫到认识,对于 JavaScript 书籍的认识或许还有些借鉴价值. 入门推荐首选书籍:<JavaScript DOM 编程艺术 > 当初读了不下 4 遍,书内容简单,易学,上手快,编程思想严谨.好的入门书,对你未来的编程都会有着深远的影响.此本书不辜负这个历史使命. 更详细的评论可以看 Realazy 在豆瓣上的评论在 豆瓣 上的评论<通往终点的过程与终点本身同样重要> 基

  • C语言编程中的联合体union入门学习教程

    联合体(union)在C语言中是一个特殊的数据类型,能够存储不同类型的数据在同一个内存位置.可以定义一个联合体使用许多成员,但只有一个部件可以包含在任何时候给定的值.联合体会提供使用相同的存储器位置供多用途的有效方式. 定义联合体 要定义联合体,必须使用union语句很相似于定义结构.联合体声明中定义了一个新的数据类型,程序不止一个成员.联合体声明的格式如下: union [union tag] { member definition; member definition; ... member

  • C语言WinSock学习笔记第1/2页

    作者:肖进 Socket(套接字) ◆先看定义: typedef unsigned int u_int; typedef u_int SOCKET; ◆Socket相当于进行网络通信两端的插座,只要对方的Socket和自己的Socket有通信联接,双方就可以发送和接收数据了.其定义类似于文件句柄的定义. ◆Socket有五种不同的类型: 1.流式套接字(stream socket) 定义: #define SOCK_STREAM 1  流式套接字提供了双向.有序的.无重复的以及无记录边界的数据流

  • JavaScript 语言精粹学习笔记第1/2页

    非常好的想法包括函数,弱类型,动态对象和一个富有表现力的对象字面量的表示法, 坏的想法包括基于全局变量的编程模型. JavaScript的函数是基于词法作用域的顶级对象.Javascript是第一个成为主流的Lambda语言.相对于Java而言,JavaScript于Lisp和Scheme有更多的共同点.它是披着C外衣的Lisp.这使得JavaScript成为一个非常强大的语言. 现在大部分变成语言都流行要求强类型.其原理在于强类型允许编译器在编译时检查错误.我们越早检查和修复错误,付出的代价越

  • C语言入门学习笔记之typedef简介

    在单片机和操作系统中 typedef 会经常用到,它可以为某一个类型自定义名称.和#define比较类似.但是又有不同的地方. typedef 创建的符号只能用于数据类型,不能用于值.而#define 创建的符号可以用于值. typedef 是由编译器来解释,而不是预处理器. typedef 使用起来更加灵活. 下面使用typedef定义一个数据类型 int main() { typedef unsigned char BYTE; BYTE c = 10; printf("%d \r\n&quo

  • Perl5 OOP学习笔记第1/2页

    在学习了Perl的基本语法之后,学习Perl的OOP,略有心得.不知道Perl各个版本之间OOP是否有区别,但是我是学习的Perl5,所以在标题上将版本号也写出来了.因为了解到PHP4和PHP5的OOP部分就有不小的差别,所以有此担心. 学习Perl的OOP,最关键的两件事情就是package和bless.只要把这两个东西搞清楚也就学会大一半了. Perl的package 感觉Perl的package和Java还真有点相似.Java的package是以CLASSPATH中的目录为根,按目录定义和

  • 揭开AJAX神秘的面纱(AJAX个人学习笔记)第1/5页

    AJAX技术是多种计算机技术的结晶,它的名称来自:Asynchronism(异步).JavaScript.And.XML这4个单词首字母,即异步JavaScript请求处理XML技术.简单的描述就是数据异步传输网页局部刷新的技术.AJAX很流行,WEB程序设计中如果不应用AJAX技术,可以说是不完善的设计.就好象黑白电视机与彩电一样,AJAX就是后者,是一种技术更新的革命! 本人学习AJAX时间并不长,仅10余天,不能说百分之百掌握,但也有所领悟.现在把自己的学习经过和体会写下来,与君共分享.

  • php 学习笔记第1/2页

    PHP概述: php是Hypertext Preprocessor(超文本预处理器)的缩写,是一种服务器端.跨平台.HTML嵌入式的脚本语言,其独特的语法混合了C语言.Java语言和Perl语言的特点,是一种被广泛应用的开源式的多用途脚本语言, 尤其适合web开发.php是b/s体系结构,属于三层结构.服务启动后,用户不用相应客户端软件,只用浏览器浏览即可以,即保存了图形化的用户界面,又大大减少了应用维护量.php是起源于自由软件,即开源软件, 使用php进行web应用程序的开发具有安全性高.跨

  • JSON学习笔记第1/2页

    利用xmlHttpRequest组件作为交互工具,利用XML作为数据传输的格式. [  XML ] 使用XML作为传输格式的优势: 1. 格式统一, 符合标准 2. 容易与其他系统进行远程交互, 数据共享比较方便 缺点: 1. XML文件格式文件庞大, 格式复杂, 传输占用带宽 2. 服务器端和客户端都需要花费大量代码来解析XML, 不论服务器端和客户端代码变的异常复杂和不容易维护 3. 客户端不同浏览器之间解析XML的方式不一致, 需要重复编写很多代码 4. 服务器端和客户端解析XML花费资源

  • 比较详细的javascript DOM 学习笔记第1/2页

    一.DOM基础1.节点(node)层次Document--最顶层的节点,所有的其他节点都是附属于它的.DocumentType--DTD引用(使用<!DOCTYPE>语法)的对象表现形式,它不能包含子节点.DocumentFragment--可以像Document一样来保存其他节点.Element--表示起始标签和结束标签之间的内容,例如<tag></tab>或者<tag/>.这是唯一可以同时包含特性和子节点的节点类型.Attr--代表一对特性名和特性值.这

  • Go语言学习笔记之反射用法详解

    本文实例讲述了Go学习笔记之反射用法.分享给大家供大家参考,具体如下: 一.类型(Type) 反射(reflect)让我们能在运行期探知对象的类型信息和内存结构,这从一定程度上弥(mi)补了静态语言在动态行为上的不足.同时,反射还是实现元编程的重要手段. 和 C 数据结构一样,Go 对象头部并没有类型指针,通过其自身是无法在运行期获知任何类型相关信息的.反射操作所需要的全部信息都源自接口变量.接口变量除存储自身类型外,还会保存实际对象的类型数据. func TypeOf(i interface{

  • Python基础语言学习笔记总结(精华)

    以下是Python基础学习内容的学习笔记的全部内容,非常的详细,如果你对Python语言感兴趣,并且针对性的系统学习一下基础语言知识,下面的内容能够很好的满足你的需求,如果感觉不错,就收藏以后慢慢跟着学习吧. 一.变量赋值及命名规则 ① 声明一个变量及赋值 #!/usr/bin/env python # -*- coding:utf-8 -*- # _author_soloLi name1="solo" name2=name1 print(name1,name2) name1 = &q

随机推荐