linux socket 客户端ip,linux---网络编程之TCP/IP的TCP socket通信过程

传统的TCP/IP通信过程依赖于socket,位于应用层和传输层之间,使得应用程序可以进行通信。相当于港口城市的码头,使得城市之间可以进行货物流通。服务器和客户端各有不同的通信流程。

一、服务器

1、建立连接阶段

调用socket(),分配文件描述符,即监听套接字

调用bind(),将套接字与本地IP地址和端口绑定

调用listen(),监听特定端口,socket()创建的套接字是主动的,调用listen使得该文件描述符为监听套接字,变主动为被动

调用accept(),阻塞等待客户端连接

2、数据交互阶段

调用read(),阻塞等待客户端发送的请求,收到请求后从read()返回,处理客户端请求

调用write(),将处理结果发送给客户端,然后继续调用read()等待客户端请求

3、关闭连接

当read()返回0的时候,说明客户端发来了FIN数据包,即关闭连接,也会调用close()关闭连接套接字和监听套接字

二、客户端

1、建立连接阶段

调用socket(),分配文件描述符

调用connect(),向服务器发送建立连接请求

2、数据交互阶段

调用write(),将请求发送给服务器

调用read(),阻塞等待服务器应答

3、关闭连接

当没有数据发送的时候,调用close()关闭连接套接字,即关闭连接,向服务器发送FIN数据报

三、TCP通信过程

01d2c5d62dad42c284e13c580c247584.png

对tcp/ip网络协议栈不熟悉的朋友可以看看这个视频:手把手带大家实现一个tcp/ip网络协议栈

四、C语言代码

1.服务器端

/* File name: server.c*/

//服务器端

#include

#include

#include

#include

#include

#include

#include

#include

#define MAXLINE 4096

#define PORT 8000

int main(void){

//定义服务器监听套接字和连接套接字

int listen_fd = -1, connect_fd = -1;//初始化为-1

struct sockaddr_in servaddr;//定义服务器对应的套接字地址

//服务器接收和发送缓冲区

char sendbuf[MAXLINE], recbuf[MAXLINE];

//初始化套接字地址结构体

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = AF_INET;//IPv4

servaddr.sin_port = htons(PORT);//设置监听端口

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//表示接收任意IP的连接请求

//创建套接字

if((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){

//如果创建套接字失败,返回错误信息

//strerror(int errnum)获取错误的描述字符串

printf("create socket error: %s(error: %d)\n", strerror(errno), errno);

exit(0);

}

//绑定套接字和本地IP地址和端口

if(bind(listen_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){

//绑定出现错误

printf("bind socket error: %s(error: %d)\n", strerror(errno), errno);

exit(0);

}

//使得listen_fd变成监听描述符

if(listen(listen_fd, 10) == -1){

printf("listen socket error: %s(error: %d)\n", strerror(errno), errno);

exit(0);

}

//accept阻塞等待客户端请求

printf("等待客户端发起连接\n");

while(1){

if((connect_fd = accept(listen_fd, (struct sockaddr*)NULL, NULL)) == -1){

printf("accept socket error: %s(error: %d)\n", strerror(errno), errno);

continue;

}

//可以一直保持连接

while(1){

//读取客户端发来的信息

ssize_t len = read(connect_fd, recbuf, sizeof(recbuf));

if(len < 0){

if(errno == EINTR){

continue;

}

exit(0);

}

printf("接收客户端的请求:%s\n", recbuf);

//向客户端发送信息

printf("回复客户端信息:");

fgets(sendbuf, sizeof(sendbuf), stdin);

write(connect_fd, sendbuf, sizeof(sendbuf));

}

//关闭连接套接字

close(connect_fd);

}

//关闭监听套接字

close(listen_fd);

}

2.客户端

/* File name: client.c */

//客户端

#include

#include

#include

#include

#include

#include

#include

#include

#define MAXLINE 4096

#define PORT 8000

int main(void){

//定义客户端套接字

int sockfd = -1;

//定义想连接的服务器的套接字地址

struct sockaddr_in servaddr;

//发送和接收数据的缓冲区

char sendbuf[MAXLINE], recbuf[MAXLINE];

//初始化服务器套接字地址

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = AF_INET;//IPv4

servaddr.sin_port = htons(PORT);//想连接的服务器的端口

servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器的IP地址

//创建套接字

if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){

printf("create socket error: %s(error: %d)\n", strerror(errno), errno);

exit(0);

}

//向服务器发送连接请求

if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){

//连接失败

printf("connect socket error: %s(error: %d)\n", strerror(errno), errno);

exit(0);

}

while(1){

//向服务器发送信息

printf("向服务器发送信息:");

fgets(sendbuf, sizeof(sendbuf), stdin);

write(sockfd, sendbuf, sizeof(sendbuf));

//从服务器接收信息

ssize_t len = read(sockfd, recbuf, sizeof(recbuf));

if(len < 0){

if(errno == EINTR){

continue;

}

exit(0);

}

printf("服务器回应:%s\n", recbuf);

}

//关闭套接字

close(sockfd);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值