栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Linux网络编程——套接字编程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux网络编程——套接字编程

相关的接口函数
(1)创建套接字
#include
#include
#include
int socket(int domain, int type, int protocol);
返回值:成功 返回套接字的文件描述符
失败 -1
参数:domain --》地址协议
IPV4地址协议 --》AF_INET或者PF_INET
IPV6地址协议 --》AF_INET6或者PF_INET6
type --》套接字类型
tcp套接字(数据流套接字,流式套接字) --》SOCK_STREAM
udp套接字(数据报套接字) --》SOCK_DGRAM
protocol --》扩展协议,一般默认设置为0
(2)绑定ip和端口号(自己的ip和端口号)
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //通用性更好,兼容ipv4和ipv6

int bind(int sockfd, const struct sockaddr_in *addr, socklen_t addrlen); //局限性,只能使用IPv4地址
int bind(int sockfd, const struct sockaddr_in6 *addr, socklen_t addrlen); //局限性,只能使用IPv6地址
参数: sockfd --》套接字的文件描述符
addr --》(重点,重点,重点)存放你要绑定的ip和端口号
struct sockaddr //通用地址结构体,兼容ipv4和ipv6
{
sa_family_t sa_family; //保存地址协议 2字节
char sa_data[14]; //存放ip和端口号 14字节
} 16字节
struct sockaddr_in //IPV4地址结构体
{
short sin_family; //地址协议
struct in_addr sin_addr; //存放要绑定的ip地址 4字节
short sin_port; //存放要绑定的端口号
sin_zero; /保证struct sockaddr_in大小跟struct sockaddr一致
}
struct in_addr
{
in_addr_t s_addr; //最终存放要绑定的ip地址
}
struct sockaddr_in6 //IPV6地址结构体
{

}
addrlen --》地址结构体的大小 sizeof()
(3) 转换函数
字节序–》数据在计算机中是如何存放的
大端序 高字节存放在低地址,低字节存放在高地址
小端序: 高字节存放在高地址,低字节存放在低地址
网络字节序:计算机网络中数据采用大端序存放
主机字节序:linux系统中数据采用小端序存放
小端序ip—》大端序ip
in_addr_t inet_addr(const char *cp);
返回值:成功 转换得到的二进制大端序ip
参数:cp --》点分十进制字符串ip
小端序端口号—》大端序端口号
uint16_t htons(uint16_t hostshort);
h —>host
to -->转换
n -->network
s -->short
返回值:成功 大端序的端口号
参数:hostshort --》小端序的端口号
(4)连接服务器
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:addr --》存放服务器的ip和端口号

(5)监听
tcp协议允许多个客户端连接同一个服务器
int listen(int sockfd, int backlog);
参数:backlog(重点) --》最多允许多少个客户端同时连接一台服务器
listen(sockfd,6);
(6)接受客户端的连接请求,愿意接听
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
返回值:(重点重点重点) 成功 新的套接字文件描述符
失败 -1
特点:(重点)
每连接一个客户端,accept都会产生新的套接字
新的套接字用来跟客户端通信
accept如果没有客户端连接,会一直阻塞,一旦有客户端连接成功,accept会解除阻塞,返回新的套接字
参数:addr --》存放目前连接成功的客户端的ip和端口号
注意:该变量不需要初始化,accept会自动将目前连接成功的客户端信息存放到这个变量地址中
addrlen --》地址长度,要求是指针
(7)研究read和write
文件IO: read的返回值 返回0表示文件读取完毕
网络编程: read的返回值 返回0表示对方断开连接了,read也不会阻塞了

(8)遇到的问题
第一个: 绑定失败,原因是地址被占用
真实原因:你绑定的端口号不会随着程序的强行退出立马释放,所以你再次运行提示这种错误(本质上就是端口号没有彻底释放)
解决方法:
第一种:更换新的端口号–》虽然可以解决问题,但是麻烦
第二种:调用系统提供的函数setsockopt()修改套接字的属性,修改成端口号可以重复使用
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
参数:sockfd --》套接字文件描述符
level --》SOL_SOCKET
optname --》SO_REUSEADDR
(9)send和recv
ssize_t send(int socket, const void *buffer, size_t length, int flags); //类似于write
返回值:成功 返回发送的字节数 失败 -1
参数:flags --》默认设置为0
ssize_t recv(int socket, void *buffer, size_t length, int flags); //类似于read
返回值:
参数:flags --》默认设置为0
MSG_WAITALL //recv在接收信息的时候必须按照length的大小接收,一个都不能少

TCP单向通信
客户端

#include "myhead.h"



int main()
{
	int tcpsock;
	int ret;
	char buf[100];
	//定义ipv4地址结构体变量
	struct sockaddr_in bindaddr;
	bzero(&bindaddr,sizeof(bindaddr));
	bindaddr.sin_family=AF_INET;
	bindaddr.sin_addr.s_addr=inet_addr("192.168.24.35");  //绑定客户端自己的ip地址
	bindaddr.sin_port=htons(10000); //绑定客户端自己的端口号
	
	//定义结构体变量存放对方(服务器)的ip和端口号
	struct sockaddr_in serveraddr;
	bzero(&serveraddr,sizeof(serveraddr));
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_addr.s_addr=inet_addr("192.168.24.201");  //服务器的ip地址
	serveraddr.sin_port=htons(20000); //服务器的端口号
	//创建tcp套接字
	tcpsock=socket(AF_INET,SOCK_STREAM,0);
	if(tcpsock==-1)
	{
		perror("创建tcp套接字!n");
		return -1;
	}
	//绑定ip和端口号
	ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
	if(ret==-1)
	{
		perror("绑定失败!n");
		return -1;
	}
	
	//连接服务器
	ret=connect(tcpsock,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
	if(ret==-1)
	{
		perror("连接服务器!n");
		return -1;
	}
	
	//发送信息给服务器
	while(1)
	{
		bzero(buf,100);
		printf("请输入要发送给服务器的信息!n");
		scanf("%s",buf);
		write(tcpsock,buf,strlen(buf));
	}
	close(tcpsock);
	return 0;
}

服务器

#include "myhead.h"



int main(int argc,char **argv)
{
	int tcpsock;
	int newsock;
	int ret;
	char buf[100];
	//定义ipv4地址结构体变量
	struct sockaddr_in bindaddr;
	bzero(&bindaddr,sizeof(bindaddr));
	bindaddr.sin_family=AF_INET;
	bindaddr.sin_addr.s_addr=inet_addr("192.168.24.201");  //绑定服务器自己的ip地址
	bindaddr.sin_port=htons(20000); //绑定服务器自己的端口号

	struct sockaddr_in clientaddr;
	bzero(&clientaddr,sizeof(clientaddr));
	int addrsize=sizeof(clientaddr);
	
	
	//创建tcp套接字
	tcpsock=socket(AF_INET,SOCK_STREAM,0);
	if(tcpsock==-1)
	{
		perror("创建tcp套接字!n");
		return -1;
	}
	printf("旧的文件描述符:%dn",tcpsock);
	//绑定ip和端口号
	ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
	if(ret==-1)
	{
		perror("绑定失败!n");
		return -1;
	}
	//监听
	ret=listen(tcpsock,8);
	if(ret==-1)
	{
		perror("监听失败!n");
		return -1;
	}
	//接收客户端的连接请求
	newsock=accept(tcpsock,(struct sockaddr *)&clientaddr,&addrsize);
	if(newsock==-1)
	{
		perror("接收客户端的连接请求失败!n");
		return -1;
	}
	printf("新的文件描述符:%dn",newsock);
	//接收信息
	while(1)
	{
		bzero(buf,100);
		ret=read(newsock,buf,100);
		//ret=read(tcpsock,buf,100);  //错误示范,用错了文件描述符
		printf("read的返回值是:%dn",ret);
		printf("客户端发送给我的信息是:%sn",buf);
	}
}

TCP双向通信:
客户端

#include "myhead.h"


int tcpsock;
void *recvservermsg(void *arg)
{
	char otherbuf[100];
	int ret;
	while(1)
	{
		bzero(otherbuf,100);
		ret=read(tcpsock,otherbuf,100);
		if(ret==0)
			break;
		printf("服务器发送过来的信息是:%sn",otherbuf);
	}
}
int main(int argc,char **argv)
{
	int ret;
	pthread_t id;
	char buf[100];
	//定义ipv4地址结构体变量
	struct sockaddr_in bindaddr;
	bzero(&bindaddr,sizeof(bindaddr));
	bindaddr.sin_family=AF_INET;
	bindaddr.sin_addr.s_addr=inet_addr("192.168.24.3");  //绑定客户端自己的ip地址
	bindaddr.sin_port=htons(atoi(argv[3])); //绑定客户端自己的端口号
	
	//定义结构体变量存放对方(服务器)的ip和端口号
	struct sockaddr_in serveraddr;
	bzero(&serveraddr,sizeof(serveraddr));
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_addr.s_addr=inet_addr(argv[1]);  //服务器的ip地址
	serveraddr.sin_port=htons(atoi(argv[2])); //服务器的端口号
	//创建tcp套接字
	tcpsock=socket(AF_INET,SOCK_STREAM,0);
	if(tcpsock==-1)
	{
		perror("创建tcp套接字!n");
		return -1;
	}
	//设置端口重复使用
	int on=1;
	setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	//绑定ip和端口号
	ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
	if(ret==-1)
	{
		perror("绑定失败!n");
		return -1;
	}
	
	//连接服务器
	ret=connect(tcpsock,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
	if(ret==-1)
	{
		perror("连接服务器!n");
		return -1;
	}
	//创建一个子线程,接收服务器回复的信息
	pthread_create(&id,NULL,recvservermsg,NULL);
	//发送信息给服务器,主线程发送
	while(1)
	{
		bzero(buf,100);
		printf("请输入要发送给服务器的信息!n");
		scanf("%s",buf);
		write(tcpsock,buf,strlen(buf));
	}
	close(tcpsock);
	return 0;
}

服务器

#include "myhead.h"


int newsock;
void *sendmsgclient(void *arg)
{
	char otherbuf[100];
	while(1)
	{
		bzero(otherbuf,100);
		printf("请输入要发送给客户端的信息!n");
		scanf("%s",otherbuf);
		write(newsock,otherbuf,strlen(otherbuf));
	}
}
int main(int argc,char **argv)
{
	int tcpsock;
	int ret;
	pthread_t id;
	char buf[100];
	//定义ipv4地址结构体变量
	struct sockaddr_in bindaddr;
	bzero(&bindaddr,sizeof(bindaddr));
	bindaddr.sin_family=AF_INET;
	bindaddr.sin_addr.s_addr=inet_addr(argv[1]);  //绑定服务器自己的ip地址
	bindaddr.sin_port=htons(atoi(argv[2])); //绑定服务器自己的端口号

	struct sockaddr_in clientaddr;
	bzero(&clientaddr,sizeof(clientaddr));
	int addrsize=sizeof(clientaddr);

	//创建tcp套接字
	tcpsock=socket(AF_INET,SOCK_STREAM,0);
	if(tcpsock==-1)
	{
		perror("创建tcp套接字!n");
		return -1;
	}
	printf("旧的文件描述符:%dn",tcpsock);
	//设置端口重复使用
	int on=1;
	setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	//绑定ip和端口号
	ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
	if(ret==-1)
	{
		perror("绑定失败!n");
		return -1;
	}
	//监听
	ret=listen(tcpsock,8);
	if(ret==-1)
	{
		perror("监听失败!n");
		return -1;
	}
	//接收客户端的连接请求
	newsock=accept(tcpsock,(struct sockaddr *)&clientaddr,&addrsize);
	if(newsock==-1)
	{
		perror("接收客户端的连接请求失败!n");
		return -1;
	}
	printf("新的文件描述符:%dn",newsock);
	//创建一个线程专门发送信息给客户端
	pthread_create(&id,NULL,sendmsgclient,NULL);
	
	//接收信息
	while(1)
	{
		bzero(buf,100);
		ret=read(newsock,buf,100);
		if(ret==0)
			break;
		//ret=read(tcpsock,buf,100);  //错误示范,用错了文件描述符
		printf("read的返回值是:%dn",ret);
		printf("客户端发送给我的信息是:%sn",buf);
	}
}

多个客户端连接同一个服务器
服务器

#include "myhead.h"



int main()
{
	int tcpsock;
	int newsock;
	int ret;
	char buf[100];
	//定义ipv4地址结构体变量
	struct sockaddr_in bindaddr;
	bzero(&bindaddr,sizeof(bindaddr));
	bindaddr.sin_family=AF_INET;
	bindaddr.sin_addr.s_addr=inet_addr("192.168.24.35");  //绑定服务器自己的ip地址
	bindaddr.sin_port=htons(10086); //绑定服务器自己的端口号

	struct sockaddr_in clientaddr;
	bzero(&clientaddr,sizeof(clientaddr));
	int addrsize=sizeof(clientaddr);
	
	
	//创建tcp套接字
	tcpsock=socket(AF_INET,SOCK_STREAM,0);
	if(tcpsock==-1)
	{
		perror("创建tcp套接字!n");
		return -1;
	}
	printf("旧的文件描述符:%dn",tcpsock);
	//绑定ip和端口号
	ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
	if(ret==-1)
	{
		perror("绑定失败!n");
		return -1;
	}
	//监听
	ret=listen(tcpsock,8);
	if(ret==-1)
	{
		perror("监听失败!n");
		return -1;
	}
	while(1)
	{
		printf("阻塞在accept位置!n");
		//接收客户端的连接请求
		newsock=accept(tcpsock,(struct sockaddr *)&clientaddr,&addrsize);
		if(newsock==-1)
		{
			perror("接收客户端的连接请求失败!n");
			return -1;
		}
		printf("新的文件描述符:%dn",newsock);
	}
	
	
}

client1-client4

#include "myhead.h"



int main()
{
	int tcpsock;
	int ret;
	char buf[100];
	//定义ipv4地址结构体变量
	struct sockaddr_in bindaddr;
	bzero(&bindaddr,sizeof(bindaddr));
	bindaddr.sin_family=AF_INET;
	bindaddr.sin_addr.s_addr=inet_addr("192.168.24.35");  //绑定客户端自己的ip地址
	bindaddr.sin_port=htons(10000); //绑定客户端自己的端口号
	
	//定义结构体变量存放对方(服务器)的ip和端口号
	struct sockaddr_in serveraddr;
	bzero(&serveraddr,sizeof(serveraddr));
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_addr.s_addr=inet_addr("192.168.24.35");  //服务器的ip地址
	serveraddr.sin_port=htons(10086); //服务器的端口号
	//创建tcp套接字
	tcpsock=socket(AF_INET,SOCK_STREAM,0);
	if(tcpsock==-1)
	{
		perror("创建tcp套接字!n");
		return -1;
	}
	//绑定ip和端口号
	ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
	if(ret==-1)
	{
		perror("绑定失败!n");
		return -1;
	}
	
	//连接服务器
	ret=connect(tcpsock,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
	if(ret==-1)
	{
		perror("连接服务器!n");
		return -1;
	}
	
	//发送信息给服务器
	while(1)
	{
		bzero(buf,100);
		printf("请输入要发送给服务器的信息!n");
		scanf("%s",buf);
		write(tcpsock,buf,strlen(buf));
	}
	close(tcpsock);
	return 0;
}

内核链表实现多个客户端连接一个服务器
服务器代码

#include "myhead.h"


//定义内核链表
struct clientlist
{
	int sock; //存放套接字
	struct list_head mypoint;
};

//初始化链表头
struct clientlist *init_list()
{
	struct clientlist *head=malloc(sizeof(struct clientlist));
	INIT_LIST_HEAD(&(head->mypoint));
	return head;
}
void *routine(void *arg)
{
	char buf[100];
	struct clientlist *p=(struct clientlist *)arg;
	while(1)
	{
		bzero(buf,100);
		printf("某个线程阻塞在read了!n");
		read(p->sock,buf,100); //接收某个客户端发送的信息
		printf("客户端发送过来的信息是:%sn",buf);
	}
}
int main()
{
	pthread_t id;
	int tcpsock;
	int newsock;
	int ret;
	char buf[100];
	
	//初始化表头
	struct clientlist *myhead=init_list(); 
	
	//定义ipv4地址结构体变量
	struct sockaddr_in bindaddr;
	bzero(&bindaddr,sizeof(bindaddr));
	bindaddr.sin_family=AF_INET;
	bindaddr.sin_addr.s_addr=htonl(INADDR_ANY);  //绑定服务器自己的ip地址
	bindaddr.sin_port=htons(10086); //绑定服务器自己的端口号

	struct sockaddr_in clientaddr;
	bzero(&clientaddr,sizeof(clientaddr));
	int addrsize=sizeof(clientaddr);
	
	
	//创建tcp套接字
	tcpsock=socket(AF_INET,SOCK_STREAM,0);
	if(tcpsock==-1)
	{
		perror("创建tcp套接字!n");
		return -1;
	}
	printf("旧的文件描述符:%dn",tcpsock);
	//绑定ip和端口号
	ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
	if(ret==-1)
	{
		perror("绑定失败!n");
		return -1;
	}
	//监听
	ret=listen(tcpsock,8);
	if(ret==-1)
	{
		perror("监听失败!n");
		return -1;
	}
	while(1)
	{
		printf("阻塞在accept位置!n");
		//接收客户端的连接请求
		newsock=accept(tcpsock,(struct sockaddr *)&clientaddr,&addrsize);
		if(newsock==-1)
		{
			perror("接收客户端的连接请求失败!n");
			return -1;
		}
		printf("新的文件描述符:%dn",newsock);
		//把文件描述符存放到链表中
		struct clientlist *newnode=malloc(sizeof(struct clientlist));
		newnode->sock=newsock;
		INIT_LIST_HEAD(&(newnode->mypoint));
		//插入到链表的尾部
		list_add_tail(&(newnode->mypoint),&(myhead->mypoint));
		
		//立马新建线程接收这个客户端发送的信息
		pthread_create(&id,NULL,routine,newnode);
	}
	
	
}

客户端代码

#include "myhead.h"



int main()
{
	int tcpsock;
	int ret;
	char buf[100];
	//定义ipv4地址结构体变量
	struct sockaddr_in bindaddr;
	bzero(&bindaddr,sizeof(bindaddr));
	bindaddr.sin_family=AF_INET;
	bindaddr.sin_addr.s_addr=htonl(INADDR_ANY);  //绑定客户端自己的ip地址
	bindaddr.sin_port=htons(20000); //绑定客户端自己的端口号
	
	//定义结构体变量存放对方(服务器)的ip和端口号
	struct sockaddr_in serveraddr;
	bzero(&serveraddr,sizeof(serveraddr));
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_addr.s_addr=inet_addr("192.168.24.3");  //服务器的ip地址
	serveraddr.sin_port=htons(10086); //服务器的端口号
	//创建tcp套接字
	tcpsock=socket(AF_INET,SOCK_STREAM,0);
	if(tcpsock==-1)
	{
		perror("创建tcp套接字!n");
		return -1;
	}
	//绑定ip和端口号
	ret=bind(tcpsock,(struct sockaddr *)&bindaddr,sizeof(bindaddr));
	if(ret==-1)
	{
		perror("绑定失败!n");
		return -1;
	}
	
	//连接服务器
	ret=connect(tcpsock,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
	if(ret==-1)
	{
		perror("连接服务器!n");
		return -1;
	}
	
	//发送信息给服务器
	while(1)
	{
		bzero(buf,100);
		printf("请输入要发送给服务器的信息!n");
		scanf("%s",buf);
		write(tcpsock,buf,strlen(buf));
	}
	close(tcpsock);
	return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1004010.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号