知识点 socket是一种编程接口 socket是一中特殊文件描述符
五要素 协议(接头暗号) 本地地址 本地端口 远程地址 远程端口 ** TCP 三次握手四次挥手**
接口转换操作
- 字节序转换
点分十进制数串转网络字节序长整形
int inet_aton(const char *string, struct in_addr*addr)
2.IP地址转换操作 结构体
- 套接字地址结构
struct sockaddr {
unsigned short sa_family; // 套接字地址簇类型,为AF_INET
char sa_data[14]; // 套接字地址数据(14位的协议地址)
};
- IPV4套接字地址结构
struct sockaddr_in{
short sin_family; // 套接字地址簇类型,为AF_INET
unsigned short sin_port; // 端口号,网络字节序
struct in_addr sin_addr; // IP地址,网络字节序
unsigned char sin_zero[8];// 填充字节
};
- IPV4地址结构
struct in_addr {
in_addr_t s_addr;
};
- IPV4地址类型
typedef unsigned int in_addr_t;
socket操作
- 创建
int socket(int domain, int type, int protocol)
2.关闭
int close(int sockfd)
int shutdown(int sockfd,int howto)
3.属性 设置
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen)
获取
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen)
4.绑定
int bind(int socket, const struct sockaddr* address, socklen_t address_len)
5.监听
int listen(int sockfd, int backlog)
6.连接
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
7.接收
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
8.接受(分客户端和服务端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
如果不需要获取客户端套接字地址,后面两个参数设置为NULL
9.发送(分客户端和服务端)
ssize_t write(int fd, const void *buf, size_t len);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
10.接收
ssize_t read(int fd, void *buf, size_t len);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen)
实践 1.特殊地址设置 2.原则 客户端/发送端 必须指定连接/发送的IP(广播地址、回环地址或者某个具体地址)。 必须指定连接/发送的port。 服务器/接受端 IP指定为通配地址、回环地址或者某个具体地址。 必须指定绑定监听/接受的port。 netstat 查看网络连接状态、socket端口打开状态
代码实现大纲图:
功能: 实现简单的服务端与服务器的交互 服务器端
#include<iostream>
#include<arpa/inet.h>
#nclude<unistd.h>
#include<strings.h>
using namespace std;
void show_connect(int fd){
struct sockaddr_in local_addr;
socklen_t local_addr_len=sizeof(local_addr);
bzero(&local_addr,local_addr_len);
getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
cout<<"local"<<inet_ntoa(local_addr.sin_addr)<<":"<<ntohs(local_addr.sin_port)<<endl;
struct sockaddr_in remote_addr;
socklen_t remote_addr_len=sizeof(remote_addr);
bzero(&remote_addr,remote_addr_len);
getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
cout<<"remote"<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
}
void* read_msg(void* fd){
int connfd=*(int*)fd;
while(true){
//读数据
char buffer[1024]={0};
int len=recv(connfd,buffer,sizeof(buffer),0);
if(len==0){
cout<<"client exit"<<endl;
break;
}else{
cout<<"client:"<<buffer<<endl;
}
}
}
void* write_msg(void* fd){
int connfd=*(int*)fd;
while(true){
//写数据
string message;
getline(cin,message);
send(connfd,mesaage.c_str(),message.szie()+1,0);
}
}
//./server ip port
int main(int argc,char* argv[]){
if(argc!=3){
cout<<"usage:"<<argv[0]<<"Ip port"<<endl;
return 1;
}
//1.监听套接字
int listenfd=socket(AF_INET,SOCK_STREAM,0);
if(listenfd==-1){
cout<<"listen socket error"<<endl;
return 1;
}
//2.绑定
struct sockaddr_in local_addr;
local_addr.sin_family=AF_INET;//协议
local_addr.sin_addr.s_addr=inet_addr(argv[1]);//IP地址
local_addr.sin_port=htons(atoi(argv[2]));//端口号
if(-1==bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
cout<<"bind error"<<endl;
return 1;
}else{
cout<<"bind success"<<endl;
}
//3.监听设置
if(listen(listenfd,10)==-1){
cout<<"listen error"<<endl;
return 1;
}else{
cout<<"listen success"<<endl;
}
//4.等待接收
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
socklen_t remote_addr_len=sizeof(remote_addr);
int connfd=accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
if(connfd==-1){
cout<<"accept error"<<endl;
return 1;
}else{
cout<<"accept success"<<endl;
cout<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
show_connfd(connfd);
}
pthread_t tids[2];
pthread_create(tids,NULL,write_msg,&connfd);
pthread_create(tids+1,NULL,read_msg,&connfd);
for(auto tid:tids){
pthread_join(tid,NULL);
}
//关闭套接字
close(connfd);
close(listenfd);
}
客户端
#include<iostream>
#include<arpa/inet.h>
#nclude<unistd.h>
#include<strings.h>
using namespace std;
void show_connect(int fd){
//获取本地址和端口
struct sockaddr_in local_addr;
socklen_t local_addr_len=sizeof(local_addr);
bzero(&local_addr,local_addr_len);
getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
cout<<"local"<<inet_ntoa(local_addr.sin_addr)<<":"<<ntohs(local_addr.sin_port)<<endl;
//获取远程地址和端口
struct sockaddr_in remote_addr;
socklen_t remote_addr_len=sizeof(remote_addr);
bzero(&remote_addr,remote_addr_len);
getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
cout<<"remote"<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
}
void* read_msg(void* fd){
int connfd=*(int*)fd;
while(true){
//读数据
char buffer[1024]={0};
int len=read(connfd,buffer,sizeof(buffer));
if(len==0){
cout<<"server exit"<<endl;
break;
}else{
cout<<"server:"<<buffer<<endl;
}
}
}
void* write_msg(void* fd){
int connfd=*(int*)fd;
while(true){
//发送消息
string message;
getline(cin,message);
write(connfd,mesaage.c_str(),message.szie()+1);
}
}
//./client ip port
int main(int argc,char* argv[]){
if(argc!=3){
cout<<"usage:"<<argv[0]<<"Ip port"<<endl;
return 1;
}
//1.创建套接字
int connfd=socket(AF_INET,SOCK_STREAM,0);
if(connfd==-1){
cout<<" socket error"<<endl;
return 1;
}
//2连接服务器
struct sockaddr_in remote_addr;
remote_addr.sin_family=AF_INET;//协议
remote_addr.sin_addr.s_addr=inet_addr(argv[1]);//IP地址
remote_addr.sin_port=htons(atoi(argv[2]));//端口号
if(-1==connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
cout<<"connect error"<<endl;
return 1;
}else{
cout<<"connect success"<<endl;
show_connect(connfd);
}
pthread_t tids[2];
pthread_create(tids,NULL,write_msg,&connfd);
pthread_create(tids+1,NULL,read_msg,&connfd);
for(auto tid:tids){
pthread_join(tid,NULL);
}
//关闭套接字
close(connfd);
return 0;
}
基于tcp/ip实现
功能:服务端实现发送信息到所有客户端 客户端传消息给服务端 让服务端帮转消息给除自己的所有客户端
服务器端
#include<iostream>
#include<arpa/inet.h>
#nclude<unistd.h>
#include<strings.h>
using namespace std;
void show_connect(int fd){
struct sockaddr_in local_addr;
socklen_t local_addr_len=sizeof(local_addr);
bzero(&local_addr,local_addr_len);
getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
cout<<"local"<<inet_ntoa(local_addr.sin_addr)<<":"<<ntohs(local_addr.sin_port)<<endl;
struct sockaddr_in remote_addr;
socklen_t remote_addr_len=sizeof(remote_addr);
bzero(&remote_addr,remote_addr_len);
getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
cout<<"remote"<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
}
./server ip port
int main(int argc,char* argv[]){
if(argc!=3){
cout<<"usage:"<<argv[0]<<"Ip port name"<<endl;
return 1;
}
//1.监听套接字
int listenfd=socket(AF_INET,SOCK_STREAM,0);
if(listenfd==-1){
cout<<"listen socket error"<<endl;
return 1;
}
//设置端口重复利用
int flag=1; setsockopt(listenfd,SQL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
//2.绑定
struct sockaddr_in local_addr;
local_addr.sin_family=AF_INET;//协议
local_addr.sin_addr.s_addr=inet_addr(argv[1]);//IP地址
local_addr.sin_port=htons(atoi(argv[2]));//端口号
if(-1==bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
cout<<"bind error"<<endl;
return 1;
}else{
cout<<"bind success"<<endl;
}
//3.监听设置
if(listen(listenfd,10)==-1){
cout<<"listen error"<<endl;
return 1;
}else{
cout<<"listen success"<<endl;
}
vector<int> fds;
thread([&fds]{
while(true){
string message;
getline(cin,message);
message="广告"+message;
for(auto fd:fds){
write(fd,message.c_str(),message.size(0+1);
}
}
}).detach();
//4.等待接收
while(true){
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
socklen_t remote_addr_len=sizeof(remote_addr);
int connfd=accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
if(connfd==-1){
cout<<"accept error"<<endl;
return 1;
}else{
cout<<"accept success"<<endl;
cout<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
show_connfd(connfd);
fds.push_back(connfd);
}
thread([connfd,&fds]{
while(true){
char buffer[1024]={0};
int n=read(connfd,buffer,1024);//读取客户端发过来的消息
if(n==0){
break;
}else{
for(auto fd:fds){ //发送消息给除了自己的所有客户端
if(fd==connfd) continue;
write(fd,buffer,1024);
}
}
}
}).detach();
close(listenfd);
}
客户端
#include<iostream>
#include<arpa/inet.h>
#nclude<unistd.h>
#include<strings.h>
using namespace std;
string name;
void show_connect(int fd){
//获取本地址和端口
struct sockaddr_in local_addr;
socklen_t local_addr_len=sizeof(local_addr);
bzero(&local_addr,local_addr_len);
getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
cout<<"local"<<inet_ntoa(local_addr.sin_addr)<<":"<<ntohs(local_addr.sin_port)<<endl;
//获取远程地址和端口
struct sockaddr_in remote_addr;
socklen_t remote_addr_len=sizeof(remote_addr);
bzero(&remote_addr,remote_addr_len);
getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
cout<<"remote"<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
}
//./client ip port
int main(int argc,char* argv[]){
if(argc!=4){
cout<<"usage:"<<argv[0]<<"Ip port name"<<endl;
return 1;
}
name=argv[3];
//1.创建套接字
int connfd=socket(AF_INET,SOCK_STREAM,0);
if(connfd==-1){
cout<<" socket error"<<endl;
return 1;
}
//2连接服务器
struct sockaddr_in remote_addr;
remote_addr.sin_family=AF_INET;//协议
remote_addr.sin_addr.s_addr=inet_addr(argv[1]);//IP地址
remote_addr.sin_port=htons(atoi(argv[2]));//端口号
if(-1==connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
cout<<"connect error"<<endl;
return 1;
}else{
cout<<"connect success"<<endl;
show_connect(connfd);
}
thread([=]{
while(true){
string message;
getline(cin,message);
message =name+":"+message;
write(connfd,mesaage.c_str(),message.szie()+1);
}
}).detach();
thread([=]{
while(true){
char buffer[1024]={0};
int len=read(connfd,buffer,sizeof(buffer));
if(len==0){
cout<<"server exit"<<endl;
break;
}else{
cout<<"server:"<<buffer<<endl;
}
}
}).detach();
//关闭套接字
close(connfd);
return 0;
}