C语言socket编程<一>socket之Winsock API

参考网址:https://blog.csdn.net/Datura_Metel/article/details/79900395

https://www.2cto.com/kf/201804/736240.html

https://blog.csdn.net/m0_37947204/article/details/80489431

https://blog.csdn.net/jinmie0193/article/details/78951055

哈工大相关课程ppt

小弟我学识浅薄,理解不到位之处请各位海涵,另请大哥提点提点!小弟我感激不尽!

目标是一篇搞懂socket编程的所有api,一篇进行实战演练。

  首先解决下面几个问题:

  1.对socket编程的理解:

  也即是:调用一些操作系统提供的api,来与应用进程进行交互。

  1.微软公司在其操作系统中采用了套接字接口 API ,形成了一个稍有不同的 API,并称之为   Windows Socket Interface,WINSOCK。 

  2.Berkeley UNIX 操作系统定义了一种 API,称为 套接字接口(socket interface),简称套接字( socket)。 

  3.AT&T 为其 UNIX 系统 V 定义了一种 API,简写 为 TLI (Transport Layer Interface)。

  这里使用的是WINSOCK

  如何标识对外的通信端点呢? IP地址+端口号 

  操作系统/进程如何管理套接字(对内)?套接字描述符(socket descriptor)是一个小整数 。

  

   类似于文件的抽象

  当应用进程创建套接字时,操作系统分配一个数据结构存储该套接字相关信息

  返回套接字描述符 

  使用TCP/IP协议簇的网络应用程序声明端点地址变量时,使用结构 sockaddr_in.

  定义结构sockaddr_in:

/*
* Socket address, internet style.
*/
struct sockaddr_in {
        short   sin_family;/*地址族(TCP/IP:AF_INET) */ 
        u_short sin_port;/*端口号   */  
        struct  in_addr sin_addr;/*IP地址   */ 
        char    sin_zero[8];/*未用(置0)   */ 
};

  

 

WSAStartup 

使用Socket的应用程序在使用Socket之前必须首先调用 WSAStartup函数 

两个参数:

 第一个参数指明程序请求使用的WinSock版本,其中高位字节指明副版本、低位字节指明主版本.

  十六进制整数,例如0x102表示2.1版

第二个参数返回实际的WinSock的版本信息

  • 指向WSADATA结构的指针 

示例代码如下:使用2.1版本的WinSock的程序代码段 :

wVersionRequested = MAKEWORD( 2, 1 );  //创建字,高字节是2,低字节是1,表示版本2.1
err = WSAStartup( wVersionRequested, &wsaData ); //返回实际的WinSock的版本信息

 

WSACleanup 

 

  应用程序在完成对请求的Socket库的使用, 最后要调用WSACleanup函数解除与Socket库的绑定并释放Socket库所占用的系统资源 

  不清理的话,在运行codeblocks的时候,常常可能会发生id.exe被占用错误。无法运行,需要去管理器找进程关掉才可以继续运行。

  此类型错误处理办法详见我其他博文。

 

socket

 

  创建套接字,操作系统返回套接字描述符(sd)

  第一个参数(协议族): protofamily = PF_INET(TCP/IP)

  第二个参数(套接字类型): 

   type = SOCK_STREAM,SOCK_DGRAM or SOCK_RAW(TCP/IP)

  第三个参数(协议号):0为默认

  例:创建一个流套接字的代码段 

struct protoent *p; 
 p=getprotobyname("tcp");  
SOCKET sd=socket(PF_INET,SOCK_STREAM,p->p_proto);  

TCP:可靠、面向连接、字节流传输、点对点

UDP:不可靠、无连接、数据报传输 

 

Closesocket  

注意c语言中,如果你不管的话,就会一直保留着资源。。

关闭一个描述符为sd的套接字

如果多个进程共享一个套接字,调用closesocket 将套接字引用计数减1,减至0才关闭

一个进程中的多线程对一个套接字的使用无计数

如果进程中的一个线程调用closesocket将一个套接字 关闭,该进程中的其他线程也将不能访问该套接字

返回值:

0:成功 

SOCKET_ERROR:失败

 

bind 

 

绑定套接字的本地端点地址 

IP地址+端口号

参数:

套接字描述符(sd)

端点地址(localaddr) • 结构sockaddr_in   

客户程序一般不必调用bind函数

服务器端?

 熟知端口号:

 IP地址? 地址通配符:INADDR_ANY

参考网站:https://www.cnblogs.com/ok-lanyan/articles/2634242.html

http://blog.chinaunix.net/uid-23193900-id-3199173.html

   有连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息,无须调用bind(),因为这种情况下只需知道目的机器的IP地址,而客户通过哪个端口与服务器建立连接并不需要关心,socket执行体为你的程序自动选择一个未被占用的端口,并通知你的程序数据什么时候打开端口。

  1.需要在建连前就知道端口的话,需要 bind
  2.需要通过指定的端口来通讯的话,需要 bind 

  本来用的是TCP,客户端就不用绑定端口了,绑定之后只能运行一个client的程序属于自己人为设定的障碍,而从服务器那边得到的客户机连接端口号(是系统自动分配的)与这边客户机绑定的端口号根本是不相关的,所以客户端绑定也就失去了意义。

  如果bind了,就绑定了服务器的端口,也就导致了绑定之后只能运行一个client的程序。

 

listen  

  置服务器端的流套接字处于监听状态

    仅服务器端调用 

    仅用于面向连接的流套接字

设置连接请求队列大小(queuesize)

返回值: 

   0:成功 

   SOCKET_ERROR:失败 

 

connect

客户程序调用connect函数来使客户套接字(sd)与特定计算机 的特定端口(saddr)的套接字(服务)进行连接

 仅用于客户端

 可用于TCP客户端也可以用于 UDP客户端

 TCP客户端:建立TCP连接

 UDP客户端:指定服务器端点地址

 

 

accept

 服务程序调用accept函数从 处于监听状态的流套接字sd 的客户连接请求队列中取出排在最前的一个客户请求, 并且创建一个新的套接字来与客户套接字创建连接通道

 仅用于TCP套接字

 仅用于服务器

 利用新创建的套接字 (newsock)与客户通信

 

send, sendto 

send函数TCP套接字(客户与服务器)调用了 connect函数的UDP客户端套接字

  假如调用了connect了,自然就知道了特定端口套接字了,无需再声明destaddr了。

 

sendto函数用于UDP服务器端套接字未调用 connect函数的UDP客户端套接字

   假如没有调用connect,自然就不知道特定端口套接字,需要声明destaddr,addrlen!!!

 

我们这里需要指出一点:

  由于UDP是无连接的,你使用connect()进行了连接,他也只是发一个:/*我要开始连接了!*/给服务器,然后就开始自顾自地用sendto()或者send()发自己地请求。connect()中,调用TCP返回成功是真的建立了连接,但是UDP并不一定真正建立了连接!!!!

  UDP就像一个任性的人,他说,我要开始做某事了,于是就不论他人是否合作,自己干了起来。

 

recv, recvfrom 

 

recv函数从TCP连接的另一端接收数据,或者从调用了connect函数的UDP客户端套接字接收服务 器发来的数据

假如调用了connect了,自然就知道了特定端口套接字了,无需再声明destaddr了。

 

recvfrom函数用于从UDP服务器端套接字与未调 用connect函数的UDP客户端套接字接收对端数据

 类似同上。

 

setsockopt, getsockopt 

 

setsockopt()函数用来设置套接字sd的选项参数

getsockopt()函数用于获取任意类型、任意状态套 接口的选项当前值,并把结果存入optval

 

 

小结:

 

 

 

 

一个容易忽略的问题:进行网络传输机器两端的“大端机器”和“小端机器“的处理:

 

网络应用的Socket API(TCP)调用基本流程 

 

 到这里,主要使用的API就说完了。

 

转载于:https://www.cnblogs.com/hitWTJ/p/9886700.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值