socket-(2)

网络编程(2)
网络编程需要使用通信地址 sockaddr_in,其中的端口和IP都要做转换,端口要从本机格式转网络格式,IP要从点分十进制转十六进制。函数:
htons() - 本机 转 网络
inet_addr() - 点分十进制 转 十六进制
ntohs() - 网络 转 本机(从网络取数据到本机)
inet_ntoa() - 十六进制 转 点分十进制

例子:简单的例子,就是将socket联通
例子1:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main(){
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd == -1) perror("socket"),exit(-1);
struct sockaddr_in addr;
addr.sin_family = AF_INET;//网络
addr.sin_port = htons(2222);//端口需要处理一下
addr.sin_addr.s_addr = //IP需要转换
inet_addr("192.168.112.137");
int res = bind(sockfd,
(struct sockaddr*)&addr,sizeof(addr));
if(res == -1) perror("bind"),exit(-1);
printf("bind ok\n");
char buf[100] = {};
int len = read(sockfd,buf,sizeof(buf));
printf("读到了%d字节,内容:%s\n",len,buf);
close(sockfd);
}

例子2:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
int main(){
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd == -1) perror("socket"),exit(-1);
struct sockaddr_in addr;
addr.sin_family = AF_INET;//网络
addr.sin_port = htons(2222);//服务器的端口
addr.sin_addr.s_addr = //服务器的IP
inet_addr("192.168.112.135");
int res = connect(sockfd,
(struct sockaddr*)&addr,sizeof(addr));
if(res == -1) perror("connect"),exit(-1);
printf("connect ok\n");
write(sockfd,"hello",5);
close(sockfd);
}

aiyq195@aiyq195-virtual-machine:~/桌面/uc/day12/day12$ ./socknetabind ok
读到了5字节,内容:hello

aiyq195@aiyq195-virtual-machine:~/桌面/uc/day12/day12$ ./socknetb
connect ok

 

TCP网络编程
编程步骤:
一对多(也实现一对一):
服务器端:
1 创建socket描述符 socket()
2 准备通信地址,用sockaddr_in
3 绑定bind(),开放权限。
4 监听客户端的连接 listen()
5 等待客户端的连接 accept(),返回一个新的socket描述符,用于与客户端的交互。
6 read() write() 读写数据
   7 close()
客户端的代码步骤不变。
listen(int sockfd,int backlog)
参数 sockfd 就是第一步的返回值
backlog就是当正在处理客户端连接时,有新的客户端连接,会把新的请求放入队列,backlog就是 这个队列的最大长度。而如果处理完毕,从队列中拿出新的请求,队列就会变短。

int accept(int sockfd,struct sockaddr* addr,socklen_t* len)
参数 sockfd 就是第一步的返回值
addr 用于存储 客户端的IP
len 是传入传出参数,传入addr的大小,传出真实的大小。
注:使用TCP编程时,socket()中的type必须用:SOCK_STREAM
accpet()函数会阻塞,直到有客户端连接才能解除。
信息交互时,服务器和客户端一定要保持读写的一致性。一个读,另外一个必须写。
例子:
例子1 tcpserver.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>

int main(){
int sockfd = socket(AF_INET,SOCK_STREAM,0);//1创建
if(sockfd == -1) perror("socket"),exit(-1);
struct sockaddr_in addr;//2 通信地址
addr.sin_family = AF_INET;
addr.sin_port = htons(2222);
addr.sin_addr.s_addr =
inet_addr("192.168.112.135");
int res = bind(sockfd, //3 绑定
(struct sockaddr*)&addr,sizeof(addr));
if(res == -1) perror("bind"),exit(-1);
printf("bind ok\n");
if(listen(sockfd,100) == -1) //4 监听
perror("listen"),exit(-1);
struct sockaddr_in from;//5 等待客户端连接
socklen_t len = sizeof(from);
int fd = accept(sockfd,(struct sockaddr*)&from,
&len);
if(fd == -1) perror("accpet"),exit(-1);
printf("客户端%s成功连接\n",
inet_ntoa(from.sin_addr));
char buf[100] = {};
read(fd,buf,sizeof(buf));
printf("buf=%s\n",buf);
write(fd,"welcome",7);
close(fd);
close(sockfd);
}


例子2: client.c

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

int main(){
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1) perror("socket"),exit(-1);
struct sockaddr_in addr;
addr.sin_family = AF_INET;//网络
addr.sin_port = htons(2222);//服务器的端口
addr.sin_addr.s_addr = //服务器的IP
inet_addr("192.168.112.135");
int res = connect(sockfd,
(struct sockaddr*)&addr,sizeof(addr));
if(res == -1) perror("connect"),exit(-1);
printf("connect ok\n");
char buf[100] = {};
while(1){
printf("请输入聊天的内容:\n");
scanf("%s",buf);//加‘\0’
//1 break;服务器不知道 客户端退出
write(sockfd,buf,strlen(buf));
if(!strcmp(buf,"bye")) break;
memset(buf,0,sizeof(buf));//清0
read(sockfd,buf,sizeof(buf));
printf("buf=%s\n",buf);
memset(buf,0,sizeof(buf));//清0
}
close(sockfd);
}

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <signal.h>
#include <string.h>

int sockfd;
void fa(int signo){
printf("关闭服务器\n");
close(sockfd);
exit(0);
}
int main(){
printf("按Ctrl+C退出服务器\n");
signal(SIGINT,fa);
sockfd = socket(AF_INET,SOCK_STREAM,0);//1创建
if(sockfd == -1) perror("socket"),exit(-1);
struct sockaddr_in addr;//2 通信地址
addr.sin_family = AF_INET;
addr.sin_port = htons(2222);
addr.sin_addr.s_addr =
inet_addr("192.168.112.135");
int reuseaddr = 1;//避免重启时 地址被占用 错误
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,
&reuseaddr,sizeof(reuseaddr));
int res = bind(sockfd, //3 绑定
(struct sockaddr*)&addr,sizeof(addr));
if(res == -1) perror("bind"),exit(-1);
printf("bind ok\n");
if(listen(sockfd,100) == -1) //4 监听
perror("listen"),exit(-1);
while(1){
struct sockaddr_in from;//5 等待客户端连接
socklen_t len = sizeof(from);
int fd = accept(sockfd,(struct sockaddr*)&from,
&len);
if(fd == -1) perror("accpet"),exit(-1);
printf("客户端%s成功连接\n",
inet_ntoa(from.sin_addr));
pid_t pid = fork();//accept()会阻塞
if(pid==0){
char buf[100] = {};
while(1){
int le = read(fd,buf,sizeof(buf));
if(le<=0) break;
printf("buf=%s\n",buf);
if(!strcmp(buf,"bye")) break;
write(fd,buf,le);
memset(buf,0,sizeof(buf));
}
close(fd); exit(0); }
close(fd);//父进程关闭描述符
}
//close(sockfd);//练习:用信号关闭sockfd。
}

 

posted on 2017-02-23 14:45  aiyq195  阅读(200)  评论(0编辑  收藏  举报

导航