【Linux学习笔记50】socket编程之TCP协议

socket

socket的意思是插座,插口的意思。那么在网络编程上,也顾名思义:两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。建立网络通信连接至少要一对端口号(socket)。
socket也为TCP/IP等协议提供了开发的接口。

网络编程的流程:

在这里插入图片描述

  • OSI模型与TCP/IP协议的对应关系如图所示
  • socket在上面的关系中充当接口(蓝色)
  • socket提供了各种各样的协议接口
  • 在APP编程中,选择socket使用合适的协议
  • 然后再通过IP协议
  • 通过驱动程序(网卡)
  • 通过硬件设备(以太网、WIFI)将信息传输

实现服务器与客户端简单通信

实现思路:

在这里插入图片描述

  • 图中的三次ACK与SYN就是著名的“三次握手“
  • 第一次握手:建立连接时,客户端向服务器端发送SYN包,并且进入SYN_SEND状态,等待服务器确认。
  • 第二次握手:服务器收到SYN包后,确认客户端的SYN包,同时也发送一个自己的SYN包以及ACK包给客户端,服务器进入SYN_RECV状态
  • 第三次握手:客户端收到服务器端的SYN+ACK包后,向服务器发送确认包(ACK),发送完毕后,完成三次握手。

代码实现:

server.c:

#include "head4sock.h"

int main(int argc, char const *argv[])
{
	if(argc != 2)
	{
		printf("Usage: %s <PORT>\n", argv[0]);
		exit(0);
	}

	// 创建一个TCP套接字
	int fd = Socket(AF_INET, SOCK_STREAM, 0); //设为IPv4的套接字

	// 绑定地址(IP:PORT)
	struct sockaddr_in srvaddr, cliaddr;
	socklen_t len = sizeof(srvaddr);
	bzero(&srvaddr, len);

	srvaddr.sin_family = AF_INET;
	srvaddr.sin_port = htons(atoi(argv[1]));
	// inet_pton(AF_INET, "192.168.1.166", &srvaddr.sin_addr);
	srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	Bind(fd, (struct sockaddr *)&srvaddr, len);

	// 设置监听套接字
	Listen(fd, 3);

	// 等待对方的连接请求
	len = sizeof(cliaddr);
	int connfd = Accept(fd, (struct sockaddr *)&cliaddr, &len);

	char peeraddr[50];
	bzero(peeraddr, 50);
	printf("new connection: %s:%hu\n",
				inet_ntop(AF_INET, &cliaddr.sin_addr, peeraddr, 50),
				ntohs(cliaddr.sin_port));

	char buf[SIZE];
	while(1)
	{
		bzero(buf, SIZE);
		if(Read(connfd, buf, SIZE) == 0)
			break;

		printf("from server: %s", buf);
	}

	close(fd);
	close(connfd);

	return 0;
}

client.c:

#include "head4sock.h"

int main(int argc, char const *argv[])
{
	if(argc != 3)
	{
		printf("Usage: %s <IP> <PORT>\n", argv[0]);
		exit(0);
	}

	// 创建一个TCP套接字
	int fd = Socket(AF_INET, SOCK_STREAM, 0);

	// 准备好对端的地址信息
	struct sockaddr_in srvaddr;
	socklen_t len = sizeof(srvaddr);
	bzero(&srvaddr, len);

	srvaddr.sin_family = AF_INET;
	inet_pton(AF_INET, argv[1], &srvaddr.sin_addr);
	srvaddr.sin_port = htons(atoi(argv[2]));

	// 连接服务端
	Connect(fd, (struct sockaddr *)&srvaddr, len);

	char buf[SIZE];
	while(1)
	{
		bzero(buf, SIZE);
		if(fgets(buf, SIZE, stdin) == NULL)
			break;

		write(fd, buf, strlen(buf));
	}

	close(fd);
	return 0;
}

head4socket.h:

#ifndef _HEAD4SOCK_H_
#define _HEAD4SOCK_H_

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <poll.h>

#define SIZE 100


ssize_t Write(int fildes, const void *buf, size_t nbyte);
int Socket(int domain, int type, int protocol);
int Setsockopt(int sockfd, int level, int optname,
	       const void *optval, socklen_t optlen);

ssize_t Read(int fildes, void *buf, size_t nbyte);
int Bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int Listen(int sockfd, int backlog);
int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int Select(int, fd_set *, fd_set *, fd_set *, struct timeval *);


#endif

wrap.c:封装函数

#include "head4sock.h"

ssize_t Write(int fildes, const void *buf, size_t nbyte)
{
	ssize_t retval = write(fildes, buf, nbyte);
	if(retval == -1)
	{
		perror("write() error");
	}

	return retval;
}

ssize_t Read(int fildes, void *buf, size_t nbyte)
{
	int ret = read(fildes, buf, nbyte);
	if(ret == -1)
	{
		perror("read() failed");
	}
	return ret;
}

int Bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	int ret = bind(sockfd, addr, addrlen);
	if(ret == -1)
	{
		perror("bind() failed");
	}
	return ret;
}

int Listen(int sockfd, int backlog)
{
	int ret = listen(sockfd, backlog);
	if(ret == -1)
	{
		perror("listen() failed");
	}
	return ret;
}

int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
	int ret = accept(sockfd, addr, addrlen);
	if(ret == -1)
	{
		perror("accept() failed");
	}
	return ret;
}

int Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	int ret = connect(sockfd, addr, addrlen);
	if(ret == -1)
	{
		perror("connect() failed");
	}
	return ret;
}

int Socket(int domain, int type, int protocol)
{
	int sockfd = socket(domain, type, protocol);
	if(sockfd == -1)
	{
		perror("socket() error");
	}

	return sockfd;
}

int Setsockopt(int sockfd, int level, int optname,
	       const void *optval, socklen_t optlen)
{
	int retval = setsockopt(sockfd, level, optname, optval, optlen);
	if(retval == -1)
	{
		perror("setsockopt() error");
	}

	return retval;
}

int Select(int nfds, fd_set *readfds, fd_set *writefds,
	   fd_set *exceptfds, struct timeval *timeout)
{
	int ret = select(nfds, readfds, writefds, exceptfds, timeout);
	if(ret == -1)
	{
		perror("select() failed");
	}
	return ret;
}

代码运行结果:

在这里插入图片描述

发布了91 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/RayCongLiang/article/details/100835840
今日推荐