Linux套接字通信

Linux Socket 通信

概念

Socket(套接字)是一种实现进程间通信的方式,与其他的IPC(interprocess-
commucation)方式相比有些特殊,Scoket不仅可以实现同一主机上的进程间通信,还可以实现不同主机进程间的通信。

理解

为了实现互联互通的现代互联网,计算机网络定义了各种通讯协议,
每个计算机都需要实现这些协议才能接入互联网,这些协议统称为网络协议栈
为了让程序员能够在网络协议栈的基础上开发应用程序和服务,操作系统提供
Socket API,现在普及非常广的微信,QQ等即时通讯软件都直接或间接的使用
者套Socket API

使用

使用Socket通信共分以下几个步骤

创建套接字 ⇒ \Rightarrow 绑定地址信息 ⇒ \Rightarrow 连接 ⇒ \Rightarrow
收(发)数据 ⇒ \Rightarrow 关闭套接字

API

通信地址信息,一般我们使用sockaddr_in,它其实是sockaddr的另一种形式
可以相互转换

struct sockaddr_in {
    short sin_family;              /* Address family */
    __be16    sin_port;            /* Port number */	  
    struct in_addr sin_addr;       /* Internet address */
    unsigned char sin_zero[8];     /* Same size as struct sockaddr */
};
struct in_addr {
	unsigned long s_addr;    //IPv4
};


socket 创建套接字

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//说明:创建套接字
//参数:
//  domain:协议族,ipv4/ipv6
//  type:套接字类型 流式/数据报/原始
//  protocal:协议 tcp/udp
//返回值
//  成功返回套接字返回类型
//  失败返回-1,并设置错误码

bind 绑定地址信息

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
//说明:套接字绑定进程地址
//参数
//	sockfd:被监听的套接字描述符
//	backlog:允许的最大连接数
//返回
//	成功返回0
//	失败返回-1,并设置错误码

listen启动监听,仅服务端需要

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
//说明:监听
//参数
//	sockfd:被监听的套接字描述符
//	backlog:允许的最大连接数
//返回
//	成功返回0
//	失败返回-1,并设置错误码

accept服务端接收连接

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//说明:阻塞进程以等待一个接入入请求
//参数	
//	sockfd:被请求接入者套接字
//	sockaddr: 请求接入者地址
//	addrlen: 请求接入者地址长度
//返回值
//	成功返回非负数整型值
//	失败返回-1

connect客户端请求连接

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//说明:请求连接
//参数
//	sockfd: 请求接入者套接字
//	addr:   被请求连接者地址
//	addrlen:被请求接入者地址长度
//返回值
//	成功返回0
//	失败返回-1,并设置错误码

send发送数据

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//说明:发送数据
//参数: 
//	sockfd: 发送对象
//	buf:数据存放的地方
//	len:buf的长度
//	阻塞
//返回值: 
//	成功返回发送的字节数
//	失败返回-1,并设置错误码

recv接收数据

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//说明:接收数据
//参数: 
//  sockfd:数据来源
//  buf:数据存放的地方
//  len:buf的长度
//  flags:0  阻塞    
//返回值: 
//  成功返回接收的字节数
//  失败返回-1,并设置错误码
//	如果断开连接返回0

Demo

server.c

#include <pthread.h>
#include <strings.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
void* send_work(void* arg){
	char buf[40];
	while (1) {
		bzero(buf, sizeof(buf));
		scanf("%s",buf);
		send(*(int*)arg, buf, sizeof(buf), 0);
	}
}
void* recv_work(void* arg){
	char buf[40];
	int recv_ret = -1;
	while (1) {
		bzero(buf, sizeof(buf));
		recv_ret = recv(*(int*)arg, buf, sizeof(buf), 0);
		if(recv_ret > 0){
			printf("%s\n",buf);
		}

	}
}
int main(int argc, char* argv[]){
	if (argc < 3) {
		printf("Usage:%s <IP> <Port>\n",argv[0]);
		return -1;
	}
	int serv_sock = socket(AF_INET, SOCK_STREAM,IPPROTO_IP);
	struct sockaddr_in serv_addr;
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
	serv_addr.sin_port = htons(atoi(argv[2]));
	if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) {
		perror("bind error");
		return -1;
	}	

	listen(serv_sock,40);
	struct sockaddr_in cli_addr;
	socklen_t cli_addr_len = sizeof(cli_addr);
	int cli_sock = accept(serv_sock, (struct sockaddr*)&cli_addr,&cli_addr_len);
	printf("Client %d has connected\n",cli_sock);

	pthread_t recv_thread;
	pthread_create(&recv_thread, NULL, recv_work,&cli_sock);
	pthread_detach(recv_thread);

	send_work(&cli_sock);
	return 0;
}

client.c


#include <pthread.h>
#include <stdio.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
void* recv_work(void *arg){
	char buf[40];
	int recv_ret = -1;
	while(1){
		bzero(buf, sizeof(buf));
		int recv_ret = recv(*(int*)(arg), buf, sizeof(buf), 0);
		if (recv_ret > 0) {
			printf("%s\n",buf);
		}
	}
}
void* send_work(void *arg){
	char buf[40];
	while (1) {
		bzero(buf, sizeof(buf));
		scanf("%s",buf);
		send(*(int*)(arg), buf, sizeof(buf), 0);
	}
}
int main(int argc, char* argv[]){
	if (argc < 3) {
		printf("Usage:%s <IP> <Port>\n",argv[0]);
		return -1;
	}
	int self_sock = socket(AF_INET, SOCK_STREAM,IPPROTO_IP);

	struct sockaddr_in serv_sock_addr;
	serv_sock_addr.sin_family = AF_INET;
	serv_sock_addr.sin_addr.s_addr = inet_addr(argv[1]);
	serv_sock_addr.sin_port = htons(atoi(argv[2]));
	int connect_ret =connect(self_sock, (struct sockaddr*)&serv_sock_addr, sizeof(serv_sock_addr));
	if(connect_ret < 0){
		perror("connect error");
		return -1;
	}

	pthread_t recv_thread;
	pthread_create(&recv_thread, NULL, recv_work, &self_sock);
	pthread_detach(recv_thread);

	send_work(&self_sock);
	return 0;
}

编译:

gcc server.c -pthread -o server
gcc client.c -pthread -o client

结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值