Linux网络编程:TCP编程实现

目录

1、前言

2、函数介绍

2.1 socket函数 与 通信域 

2.2 bind函数 与 通信结构体 

2.2.1 domain通信地址族 与 通信结构体 

2.2.2 IPv4地址族结构体 

2.2.3 通用地址族结构体 

2.2.4 示例:为套接字fd绑定通信结构体addr 

2.3 listen函数 与 accept函数 

3、代码实现

3.1 服务器端代码 

3.2 客户端代码 

3.3 构建Makefile 

4、实验结果 


1、前言

使用Linux操作系统实现TCP的客户端及服务器

TCP通信的实现过程示意图如下:

2、函数介绍

2.1 socket函数 与 通信域 

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
  • domain: 指定通信域(通信地址族),AF_INET: 使用IPv4 互联网协议;AF_INET6: 使用IPv6 互联网协议;
  • type: 指定套接字类型,TCP唯一对应流式套接字,所以选择SOCK_STREAM(数据报套接字:SOCK_DGRAM);
  • protocol: 指定协议,流式套接字唯一对应TCP,所以无需要指定协议,设为0即可。

2.2 bind函数 与 通信结构体 

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd:socket函数生成的套接字
  • addr:通信结构体
  • addrlen:通信结构体的长度

2.2.1 domain通信地址族 与 通信结构体 

2.2.2 IPv4地址族结构体 

struct sockaddr_in {
    sa_family_t    sin_family; /* 地址族: AF_INET */
    in_port_t      sin_port;   /* 网络字节序的端口号 */
    struct in_addr sin_addr;   /*IP地址结构体 */
};
/* IP地址结构体 */
struct in_addr {
    uint32_t       s_addr;     /* 网络字节序的IP地址 */
};

2.2.3 通用地址族结构体 

struct sockaddr {
    sa_family_t sa_family;
    char        sa_data[14];
}

2.2.4 示例:为套接字fd绑定通信结构体addr 

addr.sin_family = AF_INET;
addr.sin_port = htons(5001);
addr.sin_addr.s_addr = 0;//本机地址
bind(fd, (struct sockaddr *)&addr, sizeof(addr) );

2.3 listen函数 与 accept函数 

/*监听套接字*/
int listen(int sockfd, int backlog);
/*处理客户端发起的连接,生成新的套接字*/
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • sockfd: 函数socket生成的套接字
  • addr:客户端的地址族信息
  • addrlen:地址族结构体的长度 

3、代码实现

3.1 服务器端代码 

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define BACKLOG 5

int main(int argc,char *argv[])
{
	int fd,newfd,ret;
	char buf[BUFSIZ] = {};//BUFSIZ 8142
	struct sockaddr_in addr;

	if(argc < 3)
	{
		printf("%s<addr><port>\n",argv[0]);
		exit(0);
	}

	/*创建套接字*/
	fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd < 0)
	{
		perror("socket");
		exit(0);
	}
	addr.sin_family = AF_INET;
	addr.sin_port = htons(atoi(argv[2]));
	if(inet_aton(argv[1],&addr.sin_addr)==0)
	{
		fprintf(stderr,"Invalid address\n");
		exit(0);
	}
	/*地址快速重用*/
	int flag = 1,len = sizeof(int);
	if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&flag,len)==-1)
	{
		perror("setsockopt");
		exit(1);
	}
	/*绑定通信结构体*/
	if(bind(fd,(struct sockaddr *)&addr,sizeof(addr)) == -1)
	{
		perror("bind");
		exit(0);
	}
	/*设置套接字为侦听模式*/
	if(listen(fd,BACKLOG) == -1)
	{
		perror("listen");
		exit(0);
	}
	/*接受客户端的连接请求,生成新的用于和客户端通信的套接字*/
	newfd = accept(fd,NULL,NULL);
	if(newfd < 0)
	{
		perror("accept");
		exit(0);
	}
	printf("BUFSIZ = %d\n",BUFSIZ);
	while(1)
	{
		memset(buf,0,BUFSIZ);
		ret = read(newfd,buf,BUFSIZ);
		if(ret < 0 )
		{
			perror("read");
			exit(0);
		}
		else if(ret == 0)
			break;
		printf("buf = %s\n",buf);
	}
	close(newfd);
	close(fd);
	return 0;
}

3.2 客户端代码 

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define BACKLOG 5
int main(int argc,char *argv[])
{
	int fd;
	struct sockaddr_in addr;
	char buf[BUFSIZ] = {};
	if(argc < 3)
	{
		printf("%s<addr><port>\n",argv[0]);
		exit(0);
	}
	/*创建套接字*/
	fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd < 0)
	{
		perror("socket");
		exit(0);
	}
	addr.sin_family = AF_INET;
	addr.sin_port = htons(atoi(argv[2]));
	if(inet_aton(argv[1],&addr.sin_addr)==0)
	{
		fprintf(stderr,"Invalid address\n");
		exit(0);
	}
	/*向服务端发起连接请求*/
	if(connect(fd,(struct sockaddr *)&addr,sizeof(addr)) == -1)
	{
		perror("connect");
		exit(0);
	}
	while(1)
	{
		printf("Input->");
		fgets(buf,BUFSIZ,stdin);
		write(fd,buf,strlen(buf));
	}
	close(fd);
	return 0;
}

3.3 构建Makefile 

Makefile文件如下: 


CC=gcc
CFLAGS=-Wall
all:client server

clean:
	rm client server

使用make去构建服务器和客户端程序。

在服务器端传入ip地址和端口号,本机地址写0,端口号写5001。

./server 0 5001

在客户端传入ip地址和端口号,连接地址写127.0.0.1(本地回环地址),端口号写5001。 

./client 127.0.0.1 5001

4、实验结果 

通过截图可以看到,测试成功,客户端发送消息,服务器端可以接收并打印。 

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在Linux网络编程中,TCP客户端编程的流程类似于打电话的过程。首先需要创建一个用于网络通信的socket套接字,通过调用socket()函数来实现。在创建套接字时,需要指定协议类型为IPv4(AF_INET)和数据流类型为TCP(SOCK_STREAM)。函数的返回值是一个套接字描述符,用于后续的通信操作。\[2\] 接下来,需要连接到服务器端,即拨通对方的号码并确定对方是自己要找的人。通过调用connect()函数来实现。在connect()函数中,需要指定服务器的IP地址和端口号。如果连接成功,就可以开始进行数据的发送和接收。\[2\] 在TCP客户端编程中,还可以使用send()或write()函数来主动发送数据,使用recv()或read()函数来接收对方的回话。发送和接收的具体实现可以根据实际需求进行调整。\[2\] 最后,在通信结束后,需要调用close()函数来关闭套接字,类似于双方说再见挂电话的过程。这样可以释放资源并结束通信。\[2\] 在网络编程中,还需要使用结构体来表示网络地址。在Linux中,常用的网络地址结构体是sockaddr_in。该结构体包含了网络协议类型、端口号、目的地址等信息。\[1\]\[3\] 总结起来,TCP客户端编程的流程包括创建套接字、连接服务器、发送和接收数据以及关闭套接字。在实际编程中,需要使用socket()、connect()、send()、recv()和close()等函数来完成这些操作。同时,还需要使用sockaddr_in结构体来表示网络地址。 #### 引用[.reference_title] - *1* *2* [Linux 网络编程——TCP编程](https://blog.csdn.net/tennysonsky/article/details/45599027)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Linux 网络编程——TCP](https://blog.csdn.net/fansongy/article/details/6778186)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值