套接字的基本操作有:

  创建(socket)、命名(bind)、侦听(listen)、连接(accept)、关闭(shutdown)、发送(send)、接受(recv)。

下面逐个分析:

  一、创建(socket):

    函数原型:int socket(int domain, int type, int protocol);

    参数:

      domain:指定发送通信的域

        可取值:AF_UNIX:本地主机通信,与IPC类似

            AF_INET:Internet地址IPV4协议

      type:指定通信类型

        可取值:SOCK_STREAM(流套接字)、SOCK_DGRAM(数据报套接字)、SOCK_RAW(原始套接字)

      protocol:指定该套接字描述符上的一个特殊的协议,如TCP,UDP等,一般设为0

    返回值:

      成功:返回创建的套接字描述符

      失败:-1

    补充:SOCK_STREAM(流套接字)应用TCP协议,提供顺序的,可靠的,基于字节流的双向链接

         SOCK_DGRAM(数据报套接字)应用UDP协议,无链接,不可靠,不固定

       SOCK_RAW(原始套接字)提供访问互联网协议和Internal Network Interfaces的权限,只有超级用户才可使用。

  二、命名(bind)

    函数原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    参数:

      sockfd:套接字描述符

      addr:指向通用套接字的协议地址结构,包括协议、地址和端口等信息

      addrlen:协议地址结构的长度,一般为sizeof(sockaddr_in)  

    但是,一般情况addr这个参数并不采用struct sockaddr *类型,而是struct sockaddr_in,使用时要注意强制类型转换。看看struct sockaddr_in的成员:

struct sockaddr_in {
short sin_family; //16位地址协议族
u_short sin_port; //16位端口地址
struct in_addr sin_addr; //32位IP地址 unsigned char   sin_zero[8] //使结构sockaddr_in与sockaddr长度相同
};
struct in_addr {
u_long s_addr;
};

    该结构中描述IP的是一个32位整型变量,而我们平时所用的是由”.“隔开的字符串。二者之间相互转换参照这几个函数,具体使用方法参照man命令

      

unsigned long inet_addr(const char *cp);

int inet_aton(const char *cp, struct in_addr *inp);

char *inet_ntoa(struct in_addr in);

    网络通信中数据存储采用网络字节序,因此要进行主机字节序与网络字节序之间的相互转化,参照以下函数

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

    返回值:

      成功:0

      失败:-1

  三、侦听(listen)

    函数原型:int listen(int sockfd, int backlog);

    参数:

      sockfd:用socket创建的套接字描述符

      backlog:sockfd接收连接的最大数目

    返回值:

      成功:0

      失败:-1

TCP通信模型中,服务器端要完成创建、命名和侦听后才能调用accept接收客户端请求,为了提高代码重用度,这里将以上三步进行封装,代码如下:

/**************************************
函数名:CreateSock
参数:
    pSock:回传创建的侦听套接字描述符
    nPort:指定套接字侦听端口
    nMax:该套接字最大连接数
函数功能:封装套接字的创建、命名和侦听
返回值:0
**************************************/
int CreateSock(int *pSock, int nPort , int nMax)
{
struct sockaddr_in addrin;
struct sockaddr *paddr = (struct sockaddr*)&addrin; assert(pSock != NULL && nPort > && nMax > );
/*清空addrin*/
memset(&addrin, ,sizeof(addrin)); addrin.sin_family = AF_INET;
addrin.sin_addr.s_addr = htonl(INADDR_ANY);
addrin.sin_port = htons(nPort); /*创建TCP套接字描述符*/
*pSock = socket(AF_INET, SOCK_STREAM, ); /*命名套接字*/
bind(*pSock, paddr, sizeof(addrin)); /*进入侦听状态*/
listen(*pSock, nMax); return ;
}

  四、连接(accept)

    函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

    参数:

      sockfd:用socket创建的套接字描述符

      addr:指向通用套接字的协议地址结构,包括协议、地址和端口等信息      

      addrlen:协议地址结构的长度,一般为sizeof(sockaddr_in)

    返回值:

      成功:创造返回一个新的socket与客户进程通信,原sockfd仍用于套接字侦听。

这里再封装一个函数,将accept也加入其中

/**************************************
函数名:AcceptSock
参数:
    pSock:创建的新的套接字描述符与客户
        进程通信
    nSock:accept成功后依然用于套接字侦听
函数功能:接受客户端的套接字连接申请
返回值:0
**************************************/
int AcceptSock(int *pSock, int nSock)
{
struct sockaddr_in addrin;
int lSize;
assert(pSock != NULL && nSock > );
while()
{
lSize = sizeof(addrin);
memset(&addrin, , sizeof(addrin));
if((*pSock = accept(nSock, (struct sockaddr*)&addrin, &lSize)) > )
return ; else
assert();
}
}

  五、接收(recv)

    函数原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);

    参数:

      sockfd:与远程通信连接的套接字描述符

      buf:接收数据的缓冲区地址

      len:缓冲区长度

      flags:接收标志

        取值:MSG_OOB、MSG_PEEK或MSG_WAITALL

有了以上知识,我们就可以用socket进行简易通讯了,本处设计一个服务器端程序的例子,创建socket,与客户端建立连接并打印收到的数据。代码如下:

  头文件:socket.h

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <assert.h>
#include <string.h>
#include <arpa/inet.h> /**************************************
函数名:CreateSock
参数:
pSock:回传创建的侦听套接字描述符
nPort:指定套接字侦听端口
nMax:该套接字最大连接数
函数功能:封装套接字的创建、命名和侦听
返回值:0
**************************************/
int CreateSock(int *pSock, int nPort , int nMax)
{
struct sockaddr_in addrin;
struct sockaddr *paddr = (struct sockaddr*)&addrin; assert(pSock != NULL && nPort > && nMax > );
memset(&addrin, ,sizeof(addrin)); addrin.sin_family = AF_INET;
addrin.sin_addr.s_addr = htonl(INADDR_ANY);
addrin.sin_port = htons(nPort); /*创建TCP套接字描述符*/
*pSock = socket(AF_INET, SOCK_STREAM, ); /*命名套接字*/
bind(*pSock, paddr, sizeof(addrin)); /*进入侦听状态*/
listen(*pSock, nMax); return ;
} /**************************************
函数名:AcceptSock
参数:
pSock:创建的新的套接字描述符与客户
进程通信
nSock:accept成功后依然用于套接字侦听
函数功能:接受客户端的套接字连接申请
返回值:0
**************************************/ int AcceptSock(int *pSock, int nSock)
{
struct sockaddr_in addrin;
int lSize;
assert(pSock != NULL && nSock > );
while()
{
lSize = sizeof(addrin);
memset(&addrin, , sizeof(addrin));
if((*pSock = accept(nSock, (struct sockaddr*)&addrin, &lSize)) > )
return ; else
assert();
}
}

  主程序:

#include <stdio.h>
#include "socket.h" int main()
{
int nSock,pSock;
char buf[]; CreateSock(&nSock, , ); AcceptSock(&pSock, nSock); memset(buf, , sizeof(buf));    //初始化缓冲区 recv(pSock, buf, sizeof(buf), ); fprintf(stderr, buf);      //打印接收到的数据 close(pSock); close(nSock); return ;
}

由于接收函数recv默认以阻塞方式读取数据,所以未读到数据进程会进入阻塞状态。

  1、编译好可执行程序后,执行

  2、另开一个终端,查看套接字连接情况

    命令:netstat -an|grep 9001

  3、打开浏览器,地址栏输入xxx.xxx.xxx.xxx:9001,xxx为UNIX系统的IP地址,要确保浏览器与UNIX能正常通信

  4、进程收到数据后会打印出来

  

  

  这次先记到这里,其他的基本操作以后用到了再做记录。

  如果有疑问或错误,欢迎指出

TCP协议下Socket的基础编程类型的更多相关文章

  1. 基于TCP协议的socket套接字编程

    目录 一.什么是Scoket 二.套接字发展史及分类 2.1 基于文件类型的套接字家族 2.2 基于网络类型的套接字家族 三.套接字工作流程 3.1 服务端套接字函数 3.2 客户端套接字函数 3.3 ...

  2. 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

  3. tcp协议下的Socket

    import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net ...

  4. TCP协议下大数据传输IOCP乱序问题

    毕业后稀里糊涂的闭门造车了两年,自己的独立博客也写了两年,各种乱七八糟,最近准备把自己博客废了,现在来看了下这两年写的对我来说略微有点意义的文章只此一篇,转载过来以作留念. 写的很肤浅且凌乱,请见谅. ...

  5. 基于tcp协议下粘包现象和解决方案,socketserver

    一.缓冲区 每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区.write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送 ...

  6. 网络编程之TCP三次握手与四次挥手、基于TCP协议的套接字编程

    目录 TCP三次握手和四次挥手 背景描述 常用的熟知端口号 TCP概述 TCP连接的建立(三次握手) TCP四次挥手 如果已建立连接,客户端突然断开,会怎么办呢? 基于TCP协议的套接字编程 什么是S ...

  7. 自学Python-基于tcp协议的socket

    自学Python之路-Python基础+模块+面向对象自学Python之路-Python网络编程自学Python之路-Python并发编程+数据库+前端自学Python之路-django 自学Pyth ...

  8. TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q

    TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务 ...

  9. 基于TCP 协议的socket 简单通信

    DNS 服务器:域名解析 socket 套接字 : ​ socket 是处于应用层与传输层之间的抽象层,也是一组操作起来非常简单的接口(接受数据),此接口接受数据之后,交由操作系统 为什么存在 soc ...

随机推荐

  1. Java基础知识强化之IO流笔记13:递归之不死神兔问题(斐波那契数列)

    1.这个问题是如下的:    有一对兔子,从出生后第3个月起,每个月都生一对兔子,小兔子长到第3个月又生一对兔子,加入兔子都不死,问第20个月兔子的对数? 分析:我们找规律 兔子对数第1个月:   1 ...

  2. redisbook笔记——redis内存映射数据结构

    虽然内部数据结构非常强大,但是创建一系列完整的数据结构本身也是一件相当耗费内存的工作,当一个对象包含的元素数量并不多,或者元素本身的体积并不大时,使用代价高昂的内部数据结构并不是最好的办法. 为了解决 ...

  3. eclipse打包jar时包含第三方jar包的相关问题

    我用的是mars4.5版本的eclipse 需求:要把写好的工程打成jar包,并能直接运行.工程用了若干个第三方jar. 在打包的时候,eclipse提供的打包方法不能引用第三方jar包,导致了出现C ...

  4. [转] iOS SDK:iOS调试技巧

    原文:  http://www.cocoachina.com/ios/20130517/6225.html 为什么你的数组包含3个项目而不是5个?为什么你的游戏运行缓慢?这些都跟调试有关,调试是开发过 ...

  5. 【OpenSSL】创建证书

    [-] 1生成根证书 1 生成RSA私钥 2 生成证书请求 3 签发自签名证书 2 生成用户证书 1 生成RSA私钥 2 生成证书请求 3 签发证书   1)生成根证书 1.1) 生成RSA私钥 op ...

  6. Java Calendar 计算时间差

    public static void main(String[] args) { Calendar c=Calendar.getInstance(); int y=2016;//年 int M=1;/ ...

  7. 第一个shell编程,输出hello world!

    在计算机科学中,Shell俗称壳(用来区别于核),是指“提供使用者使用界面”的软件(命令解析器).它类似于DOS下的command和后来的cmd.exe.它接收用户命令,然后调用相应的应用程序.--- ...

  8. 设计模式C++实现(1)——工厂模式

    该文章转载自: http://blog.csdn.net/wuzhekai1985 软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径.设计模式中运用了面向对象编程语言的重要特性:封装 ...

  9. WebForm,Winfrom下拉框添加全部行

    WebForm: dropPostalLineNo.DataSource = "数据源";        dropPostalLineNo.DataTextField = &quo ...

  10. js 实现分割条

    js 实现 切分条效果, 为了熟悉js  写法,纯javascript 脚本编写 简单介绍几个函数: setCapture()函数的作用就是将后续的mouse事件都发送给这个对象, releaseCa ...