首先要明白,三元组可以标识唯一主机的唯一应用程序,网络中进程的通信就可以利用三元组的标志与其他进程之间进行交互。三元组是:ip地址、端口号和连接(通讯链路)。或者也可以说是五元组:(协议,本地地址,本地端口号,远地地址,远地端口号)
socket编程建立连接的流程如下:

1.什么是socket

网络中的进程是利用socket来进行通信的。socket对于linux/Unix来说是一个特殊的文件,一些socket函数会进行读写io、关闭、打开等功能

2.socket的基本操作

2.1 socket()函数

int socket (int domain, int type, int protocol)


需要注意的是上面的type和protocol并不能随意组合,如SOCK_STREAM不可以跟IPPROTO_UDP组合

2.2 blind()函数

bind()函数会把一个地址族中的特定地址赋给socket,例如对应AF_INET,AF_INET6,就是把一个ipv4或ipv6的端口号付给socket

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数的三个参数:
addr是一个指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同,如ipv4的是:

struct sockaddr_in {sa_family_t    sin_family; /* address family: AF_INET */in_port_t      sin_port;   /* port in network byte order */struct in_addr sin_addr;   /* internet address */
};/* Internet address. */
struct in_addr {uint32_t       s_addr;     /* address in network byte order */
};

需要注意的是,在将一个地址转移到socket中时,需要先将主机字节序转换为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。

2.3 listen()函数

作为要给服务器,在调用socket(),bind()之后,就会调用listen()函数来监听这个socket,如果客户端这时候调用connect()发出连接请求,服务器端就会接收到这个请求。

int listen(int sockfd, int backlog);

2.4 connect()函数

客户端通过调用connect函数来建立与tcp服务器的连接

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

2.5 accept()函数

tcp服务器端依次调用socket(),bind(),listen()之后,就会监听指定的socket地址了。tcp客户端一次调用socket(),connet()后就向tcp服务器端发送了一个连接请求,TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以进行网络I/O操作了。

int accept(int sockfd, struct sockaddr *addr,socklen_t *addrlen);

2.6 read(),write()等函数

连接已经建立好了,可以调用网络I/O进行读写了,即使实现了网络中不同进程之间的通信,网络I/O有以下几组:
• read()/write()
• recv()/send()
• readv()/writev()
• recvmsg()/sendmsg()
• recvfrom()/sendto()
函数声明如下:

#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);ssize_t write(int fd, const void *buf, size_t count);#include <sys/types.h>#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);ssize_t recv(int sockfd, void *buf, size_t len, int flags);ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

read负责从fd中读取内容,读取成功时,read返回实际所读的字节数,如果返回值为0则表明已经读到文件结尾了,小于0表示出现了错误,如果错误为enter说明是由中断引起的。如果是ECONNREST表示网络连接出了问题。
write函数将buf中的nbytes字节内容写入文件描述符fd,成功时返回写的字节数。失败时返回-1,。在网络程序中,当我们向套接字描述符写时有两种可能
• write的返回值大于0,表示写了部分或者是全部的数据。
• 返回值小于0,说明出现了错误
其他的函数也类似

2.7 close()函数

在服务器和客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的socket描述字。

int close(int fd);

close一个TCP socket时把该socket标记为关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为read或write的第一个参数。
注意:close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0,才会触发TCP客户端向服务器端发送终止连接请求。

2.8 inet_ntop函数与ipnet_pton函数

函数中的p和n分别代表表达(presentation)和数值(numeric),二者适用于IPv4及IPv6。地址的表达格式通常为ASCII码字符串,如常用的210.26.48.46,数值格式则是存放到套接字地址结构的二进制值。
函数声明如下:

#include <arpe/inet.h>
//将点分十进制的ip地址转化为用于网络传输的数值格式
int inet_pton(int family, const char *strptr, void *addrptr);
// 返回值:若成功则为1,若输入不是有效的表达式则为0,若出错则为-1//将数值格式转化为点分十进制的ip地址格式
const char * inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
//返回值:若成功则为指向结构的指针,若出错则为NULL

参数含义:

2.9 fread函数(读取文件)

从输入文件(数据流)中读取size*count字节 存放到buffer中,并返回内容数量
函数原型:

size_t   fread(  void *buffer,  size_t  size,  size_t  count,  FILE  *stream  )


举个栗子:从fp里读取100个字节,可用以下语句:
fread(buffer,1,100,fp);
fread(buffer,100,1,fp);
fread(buffer,10,10,fp);

3 试验结果

发送端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>#define MAXLINE 4096int main(int argc, char** argv)
{int    sockfd,n;char   recvline[4096],sendline[4096];struct    sockaddr_in servaddr;#如果命令行输入参数不为2,就指示用法if( argc != 2){printf("usage:./client <ipaddres>\n");exit(0);}#对sockfd进行赋值,同时判断是否出错if ( (sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {printf("create socket error:%s(errno:%d)\n",strerror(errno),errno);exit(0);}#memset(void *s,int ch,size_tn) 对servaddr地址段内容清零memset(&servaddr,0,sizeof(servaddr));#socket赋值,协议、端口servaddr.sin_family = AF_INET;servaddr.sin_port = htons(6666);#赋IP,将点分文本的IP地址转换为二进制网络字节序”的IP地址if(inet_pton(AF_INET,argv[1], &servaddr.sin_addr)<=0){printf("inet_pton error for %s\n",argv[1]);exit(0);}#建立连接if (connect (sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0){printf("conect error:%s(error:%d)\n",strerror(errno),errno);exit(0);}printf("send msg to server:\n");#fgets(str,n,stream)从stream中最多读取n个字符放到str中fgets(sendline,4096,stdin);#send(sockfd,buf,size,flags)若返回值小于0,出错if (send(sockfd,sendline,strlen(sendline),0)<0){printf("send msg error:%s(error:%d)\n",strerror(errno),errno);exit(0);}close(sockfd);exit(0);
}

发送端实验结果:

接收端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>#define MAXLINE 4096int main(int argc, char** argv)
{int    listenfd, connfd;struct sockaddr_in     servaddr;char    buff[4096];int     n;if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);exit(0);}memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(6666);if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);exit(0);}if( listen(listenfd, 10) == -1){printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);exit(0);}printf("======waiting for client's request======\n");while(1){if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){printf("accept socket error: %s(errno: %d)",strerror(errno),errno);continue;}n = recv(connfd, buff, MAXLINE, 0);buff[n] = '\0';printf("recv msg from client: %s\n", buff);close(connfd);}close(listenfd);
}

接收端实验结果:

代码来源于网络,侵删

socket编程流程与函数(实用篇)相关推荐

  1. socket编程流程及函数详解

    socket编程流程及函数详解-服务器端 一.创建socket 二.命名socket 2.1通用的socket地址结构体 2.2专用socket地址 三.监听socket 四.接受连接 五.总结 一. ...

  2. Socket编程流程梳理

    Socket编程流程 服务端:socket->bind->listen->accept->send/recv->closesocket 客户端:socket->bi ...

  3. SOCKET编程中,select()函数的作用

    SOCKET编程中,select()函数的作用Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect.accep ...

  4. Java TCP/UDP socket 编程流程总结

    最近正好学习了一点用java socket编程的东西.感觉整体的流程虽然不是很繁琐,但是也值得好好总结一下. Socket Socket可以说是一种针对网络的抽象,应用通过它可以来针对网络读写数据.就 ...

  5. socket编程的 sendto 函数

    http://see.xidian.edu.cn/cpp/html/372.html 相关函数:send, sendmsg, recv, recvfrom, socket 头文件:#include & ...

  6. socket编程:WSAStartup函数详解

    文章目录 1. 函数原型和使用 2. 功能 3. 参数1:`WORD wVersionRequested` 4. 参数2:LPWSADATA lpWSAData 5. 返回值 int 官方文档:htt ...

  7. Socket编程之简单介绍

    一:套接字编程相关知识点 Socket概念:套接字是一种通信机制,凭借这种机制,客户/服务器系统的开发工作既可以在本地单机进行,也可以跨网络进行. 网络中的进程是通过socket来通信的.socket ...

  8. unix环境高级编程基础知识之第一篇

    陆陆续续看完了圣经第一章,熟悉了unix的整个编程流程,c语言的用处在这里得到伸张. 从unix的体系结构,原来操作系统包括内核及一些其他软件,我们常常误称为linux内核为操作系统,这俨然成为一种共 ...

  9. 【Linux】SOCKET编程

    传统的进程间通信借助内核提供IPC机制进行,但是只能限制于本机通信,若要进行跨机通信,就要使用网络通信. ​ 网络通信的本质是借助内核提供SOCKET伪文件的机制进行通信,实际上是使用了文件描述符,因 ...

最新文章

  1. 《2018-2019世界智能手机AI智商测试报告》发布会将在京举办
  2. assembly plugin实现自定义打包
  3. JNI基础 c语言调用java方法
  4. 敲代码4年,发现C语言里几个有意思的问题
  5. 计蒜客 《程序设计竞赛体验课程》第一部分 快速提升代码能力
  6. 使用solrj和EasyNet.Solr进行原子更新
  7. IntelliJ IDEA Maven Mybatis generator 自动生成代码 MAC系统
  8. [Buzz Today]2012.05.10
  9. 美好消费品牌榜单TOP 5公布;迪卡侬集团正式宣布参展第四届进博会 | 美通企业日报...
  10. ubuntu安装vmplayer出现问题的解决方法
  11. android 教学ppt下载 百度云,百度云盘使用教程ppt课件.ppt
  12. 市场营销商业指标统计分析
  13. 病毒制作实践小记:运行关机、蓝屏炸弹、进程关闭、拓展名病毒
  14. 多线程爬取NCBI数据库文献
  15. 【mysql】mysql数据备份与恢复
  16. github-一个视频图片下载工具-lux(annie)
  17. STM32CubeMX入门使用一
  18. linux to go把linux系统装进U盘里随插随用
  19. iphone4 刷机记录
  20. QQ搜集用户数据是空穴来风吗?(二)

热门文章

  1. python2.X在linux上的安装
  2. C#与C++之间dll的二维(多维)数组传递
  3. 理解什么是真正的架构,架构需要的几种思维?
  4. Maven 搭建多模块企业级项目
  5. 在线机器学习FTRL(Follow-the-regularized-Leader)算法介绍
  6. spark出现task不能序列化错误的解决方法 org.apache.spark.SparkException: Task not serializable
  7. 实力封装:Unity打包AssetBundle(二)
  8. Chatbot大牛推荐:AI、机器学习、深度学习必看9大入门视频
  9. Xmanager企业版激活成功全过程
  10. 使用github时因fatal: remote origin already exists错误,无法提交