临文乍了了,彻卷兀若无。这篇文章主要讲述Linux(程序设计):41---TCP网络编程相关的知识,希望能为你提供帮助。
一、socket()函数
文章图片
【Linux(程序设计):41---TCP网络编程】
- ?服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束?
服务端通信步骤如下:客户端通信步骤如下:
- ?socket(); //创建一个socket?
- ?bind(); //绑定IP和端口?
- ?listen(); //监听是否有客户端介入?
- ?accept(); //接受客户端的请求?
- ?read(); //读取客户端发来的消息?
- ?write(); //向客户端发送消息?
- ?close(); //关闭套接字?
- ?socket(); //创建一个socket?
- ?connect(); //连接某个服务端?
- ?read(); //读取服务端发来的消息?
- ?write(); //向服务端发送消息?
- ?close(); //关闭套接字?
- ?#include< sys/types.h> ?
- ?#include<
sys/socket.h>
?
int socket(int protofamily, int type, int protocol);
二、bind()函数
?域参数指定通信域;这将选择用于通信的协议系列。这些族在< sys/socket.h> 中定义?
- ? 参数1:即协议域,又称为协议族(family)?
?AF_INET用ipv4地址(32位的)与端口号(16位的)的组合AF_INET6IPV6的?
?AF_LOCAL/或者AF_UNIX(Unix域socket)?
?用一个绝对路径名作为地址。本地通信AF_ROUTE? ?AF_IPXIPX-Novell协议AF_PACKET低层包接口包AF_NETLINK内核用户界面设备?
? 参数2:指定socket类型,与第三个参数有关?
套接字具有指定的类型,该类型指定通信语义
并不是所有的协议族都实现了这些协议类型,例如,AF_INET协议族就没有实现SOCK_SEQPACKET协议类型。
?SOCK_STREAM字节流套接字。?提供序列化的、可靠的、双向连接的字节流。支持带外数据传输(TCP使用)?SOCK_DGRAM数据报套接字。(UDP使用)支持数据报(固定最大长度的无连接、不可靠的消息)SOCK_RAW原始套接字。?RAW类型,提供原始网络协议访问?SOCK_RDM?提供了一个不保证排序的可靠数据报层。不过可能数据会有乱序?SOCK_PACKET专用类型。?不能在通用程序中使用,它直接从设备驱动接受数据?SOCK_SEQPACKET有序分组套接字。?序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统调用时数据需要将全部数据读出
参数2的socket类型都有一个默认的协议,如果想使用默认的协议,参数3填0即可
- ? 参数3:指定协议类型?
?IPPROTO_TCP? TCP传输协议(SOCK_STRAM默认使用) ?IPPTOTO_UDP? UDP传输协议(SOCK_DGRAM默认使用) ?IPPROTO_SCTP? STCP传输协议 ?IPPROTO_TIPC? TIPC传输协议
?返回值:?
- ?socket创建成功:?返回一个socket描述符(sockfd),这个描述字不是固定的,为int类型
- ?socket创建失败:?返回-1,并设置errno变量的值
?errno变量?
?EACCES?没有权限建立制定的protofamily的type的socket?EAFNOSUPPORT?不支持所给的地址类型?EINVAL?不支持此协议或者协议不可用?EMFILE?进程文件表溢出?ENFILE?已经达到系统允许打开的文件数量,打开文件过多?ENOBUFS/ENOMEM?内存不足。socket只有到资源足够或者有进程释放内存?EPROTONOSUPPORT?制定的协议type在domain中不存在
- 若socket创建失败,就会设置errno为相应的值,用户可以检测errno判断出现什么错误
?什么是socket描述符????
- 我们在使用C语言用fopen()会返回一个文件指针,这个文件指针就代表这个这个文件
- 在Linux中,我们使用sokcet()函数打开一个socket文件,会返回一个socket描述符,这个描述符就代表着这个socket。描述符也称描述字
- ?功能:?bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket
- ?#include< sys/types.h> ?
- ?#include<
sys/socket.h>
?
int bind(int sockfd, const struct sockaddr*addr, socklen_taddrlen);
三、listen()函数
- ?参数1: 服务端的socket描述符?
- ?参数2:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址(IP、端口号)?
- ?参数3:对应的地址的长度。服务器在启动的时候都会绑定一个地址(如ip地址+端口号)?
?返回值(int类型)?
- ?建立成功:成功返回0?
- ?建立失败:返回-1,并设置errno变量的值?
- ?功能:?作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求
- ?#include< sys/types.h> ?
- ?#include<
sys/socket.h>
?
int listen(int sockfd, int backlog);
四、connect()函数
- ?参数1:服务端的socket描述符?
- ?参数2:相应socket可以排队的最大连接个数 ?
?返回值(int类型)?
- ?建立成功:成功返回0?
- ?建立失败:返回-1,并设置errno变量的值?
- ? 功能:?客户端通过调用connect函数来建立与服务器的连接
- ?#include< sys/types.h> ?
- ?#include<
sys/socket.h>
?
int connect(intsockfd, const struct sockaddr*addr, socklen_t a ddrlen);
五、accept()函数
- ?参数1:客户端的socket描述符?
- ?参数2:服务器的socket地址?
- ?参数3:服务器socket地址的长度?
?返回值(int类型)?
- ?建立成功:成功返回0?
- ?建立失败:返回-1,并设置errno变量的值?
- ?功能:?服务器监听到这个请求之后,就会调用accept()函数去接收客户端的请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类似于普通文件的读写I/O操作
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
六、write()函数
- ?参数1:服务端的socket描述符?
- ?参数2:一个const struct sockaddr *指针,用来保存服务端的socket地址(IP、端口等信息)。如果不想保存服务端的信息,这个参数可以设置为NULL?
- ?参数3:客户端的socket地址长度(参数2服务端指针地址大小)。如果参数2为NULL,此处也可以设置为为NULL?
?返回值(int类型)?
- ?接收成功:返回connect_fd?
- ?接收失败:返回负数?
- #include< unistd.h>
- 发送数据
ssize_t write(int fd, const void *buf, size_t count);
七、read()函数
- ?参数1:若为服务端(为accept函数的返回值)。若为客户端(为自己socket描述符)?
- ?参数2:需要发送的字符串?
- ?参数3:每次发送的数据的字节数?
?返回值(ssize_t类型)?
- ?传递成功:返回发送的数据的字节大小?
- ?传递失败:返回-1,并设置errno变量的值?
?errno变量?
- ?EINTR:表示在写的时候出现了中断错误?
- ?EPIPE:网络连接出现了问题(对方已经关闭了连接) ?
- #include< unistd.h>
- 接收数据
ssize_t read(int fd, void *buf, size_t count);
八、close()函数
- ?参数1:若为服务端(为accept函数的返回值)。若为客户端(为自己socket描述符)?
- ?参数2:为接收数据的缓冲区?
- ?参数3:每次接收数据的字节数?
?返回值?
- ?成功:返回接收的数据的字节大小?
- ?失败:返回-1,并设置errno变量的值?
?errno变量?
- ?EINTR:?说明读是由中断引起的
- ?ECONNREST:?表示网络连接出了问题
- 关闭相应的socket描述符
- #include <
unistd.h>
int close(int fd);
服务端
- ? 参数:对应的socket描述符?
#include < stdio.h>
#include < string.h>
#include < sys/types.h>
#include < sys/socket.h>
#include < unistd.h>
#include < pthread.h>
#include < netinet/in.h>
#include < arpa/inet.h>
static void usage( const char* proc )
printf("Please use %s [ip] [port]\\n",proc);
void thread_run( void * arg )
printf("create a new thread\\n");
int fd=(int)arg;
char buf[1024];
while(1)
memset(buf,\\0,sizeof(buf));
ssize_t _s=read(fd,buf,sizeof(buf)-1); //读取客户端的数据
if(_s> 0)
buf[_s]=\\0;
printf("client say : %s\\n",buf);
memset(buf,\\0,sizeof(buf));
printf("please write :");
fflush(stdout);
ssize_t _s2=read(0,buf,sizeof(buf)-1); //输入数据
if(_s2> 0)
write(fd,buf,strlen(buf)); //放出去
int main( int argc,char *argv[] )
if(argc!=3)
usage(argv[0]);
exit(0);
//1.create socket
int sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sock< 0)
printf("Create socket error\\n");
return 1;
printf("Create socket success\\n");
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(atoi(argv[2]));
local.sin_addr.s_addr=inet_addr(argv[1]);
//2.bind
if(bind(sock,(struct sockaddr*)& local,sizeof(local))< 0)
printf("Bind error\\n");
close(sock);
return 2;
printf("Bind success\\n");
//3.listen
if(listen(sock,10)< 0)
printf("Listen error\\n");
close(sock);
return 3;
printf("Listen success\\n");
//4.accept
struct sockaddr_in peer;
socklen_t len=sizeof(peer);
while(1)//不断接受客户端的接入
int fd=accept(sock,(struct sockaddr*)& peer,& len);
if(fd< 0)
perror("accept error\\n");
close(sock);
return 4;
printf("get connect,client ip is %s port is %d\\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
pthread_t id;
pthread_create(& id,NULL,thread_run,(void*)fd); //有客户端接入,就创建新的线程
pthread_detach(id);
close(sock);
return 0;
客户端
#include < stdio.h>
#include < stdlib.h>
#include < string.h>
#include < sys/socket.h>
#include < sys/types.h>
#include < errno.h>
#include < netinet/in.h>
#include < arpa/inet.h>
#include < unistd.h>
void usage( const char *proc )
printf("Please use %s [ip] [port]\\n",proc);
int main( int argc, char *argv[] )
if(argc!=3)
usage(argv[0]);
exit(0);
//1.create socket
int sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sock< 0)
printf("Create socket error\\n");
return 1;
struct sockaddr_in remote;
remote.sin_family=AF_INET;
remote.sin_port=htons(atoi(argv[2]));
remote.sin_addr.s_addr=inet_addr(argv[1]);
//2.connect
if(connect(sock,(struct sockaddr*)& remote,sizeof(remote))< 0)
printf("Connect failed,reasons:%s\\n",strerror(errno));
close(sock);
return 2;
printf("Connect success\\n");
char buf[1024];
while(1)
memset(buf,\\0,sizeof(buf));
printf("Please write:");
fflush(stdout);
ssize_t _s=read(0,buf,sizeof(buf)-1); //输入要发送的数据
if(_s> 0)
buf[_s-1]=\\0;
write(sock,buf,strlen(buf)); //发送数据
_s=read(sock,buf,sizeof(buf)-1); //接受数据
if(_s> 0)
if(strncasecmp(buf,"quit",4)==0)
printf("quit\\n");
break;
buf[_s-1]=\\0;
printf("read is:%s\\n",buf);
close(sock);
推荐阅读
- Linux-find命令
- Linux中yum和apt-get
- Linux-SNAT和DNAT
- 智慧化水务(降低污水处理过程中人力能耗成本)
- 刷题打卡第二天(数组(快慢指针法))
- Linux中的计划任务—Crontab调度重复执行的任务
- #yyds干货盘点# Java 基础 - 面向对象的三大特性
- Linux系统编程应用 Linux Input子系统
- Linux卸载MySQL