首页 技术 正文
技术 2022年11月16日
0 收藏 949 点赞 2,964 浏览 7841 个字

  经过几天高强度的学习,对套接字的编程有了初步的认识,今天对这几天所学的知识总结一下;首先简单阐述一下tcp通信;

  TCP提供的是可靠的,顺序的,以及不会重复的数据传输,处理流控制,由于TCP是可靠的,连接的,顺序的,所以TCP一般用于都应用于对传输的完整性,正确性要求严的场合;编写基于tcp的服务器-客户端模型的程序简单流程如下:

  服务器端:

  (1)调用socket()创建一个套接口

  (2)调用bind()函数是服务器进程与一个端口绑定

  (3)调用listen()设置客户接入队列的大小

  (4)调用accept()接受一个连接,如果介入的队列不为空,则返回一个已连接的套接口描述符,

  (5)调用sned()和recv()函数用来在已连接的套接口间进行发送和接收数据

  客户端:

  (1)调用socket()创建套接字

  (2)调用connect()函数向服务器发送连接请求;

  (3)调用send()函数和recv()函数

  下面是服务器端的代码;

 #include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h> //server
int main()
{
int fd = ;
int nfd = ;
int ret = ;
unsigned char data[] = {}; fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(fd < ) {
perror("socket");
return ;
}
/*服务端信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons();
ser.sin_addr.s_addr = htonl(0xc0a8010a);//192.168.1.10
struct sockaddr_in clt;
int len = ; /*绑定*/
ret = bind(fd, (struct sockaddr *)&ser, );
if(ret < ) {
perror("bind");
return ;
} /*监听*/
ret = listen(fd, );
if(ret == -) {
perror("listen");
return ;
} /*接收连接,并且返回一个新的套接字描述符nfd*/
nfd = accept(fd, (struct sockaddr *)&clt, &len);
if(ret < ) {
perror("accept");
return ;
} /*接收*/
ret = recv(nfd, data, , );
if(ret < ) {
perror("recv");
return ;
}
printf("clt said: %s\n", data);
close(fd); return ;
}

服务器端

 #include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h> //client
int main()
{
int sock_fd = ;
int ret = ;
unsigned char *buf = "hello, hao ara you"; /*创建一个套接口*/
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock_fd < ) {
perror("socket");
return ;
} /*服务端信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons();
ser.sin_addr.s_addr = inet_addr("192.168.1.10"); //建立链接
ret = connect(sock_fd, (struct sockaddr *)&ser, );
if(ret < ) {
perror("connect");
return ;
} /*发送*/
ret = send(sock_fd, buf, strlen(buf), );
if(ret < ) {
perror("send");
return ;
} close(sock_fd);
return ;
}

客户端

上面程序是基于tcp的简单通信,下面我们利用tcp实现一个服务器多个客户机;要实现一对多,就要使用线程编程,服务器端在不断监听中,如果有连接请求的话,就用通过 accept函数接受并创建一个线程来处理。线程的创建函数为int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg);

  下面是这个程序的源码

 #include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h> #define PORT 9527 void *function(void *d);//线程要执行的函数 int main()
{
/*创建套接口*/
pthread_t pid= ;
int nfd = ;
int fd = ;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(fd < ) {
perror("sock");
return ;
}
/*服务器信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(PORT);
ser.sin_addr.s_addr = inet_addr("192.168.1.10");
struct sockaddr_in clt;
int len = ; /*绑定*/
int ret = bind(fd, (struct sockaddr *)&ser, );
if(ret == -) {
perror("bind");
return ;
} /*监听*/
ret = listen(fd, );
if(ret < ) {
perror("listen");
return ;
} while() {
/*接受链接*/
nfd = accept(fd, (struct sockaddr *)&clt, &len);
if(nfd < ) {
perror("accept");
return ;
} /*创建一个线程*/
ret = pthread_create(&pid, NULL, function, (void *)nfd);
if(ret != ) {
perror("pthread_create");
return ;
} pthread_join(pid, NULL); close(nfd);
} close(fd);
return ;
} void *function(void *d)
{
unsigned char buf[] = {};
int nfd = (int )d;
int ret = ; memset(buf, , );
ret = recv(nfd, buf, , );
if(ret < ) {
perror("recv");
return NULL;
}
printf("client said: %s\n", buf); ret = send(nfd, "recv ok", , );
if(ret < ) {
perror("send");
return NULL;
} }

server

 #include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h> #define PORT 9527 int main(int argc, char **argv)
{
if(argc != ) {
printf("using %s <ip address> <message>\n", argv[]);
return ;
}
/*创建套接口*/
int fd = ;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(fd < ) {
perror("socket");
return ;
} /*服务器信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(PORT);
ser.sin_addr.s_addr = inet_addr(argv[]); /*创建链接*/
int ret = connect(fd, (struct sockaddr *)&ser, );
if(ret < ) {
perror("connect");
return ;
} /*访问*/
ret = send(fd, argv[], strlen(argv[]), );
if(ret < ) {
perror("send");
return ;
} char buf[] = {};
ret = recv(fd, buf, , );
if(ret < ) {
perror("recv");
return ;
}
printf("server: %s\n", buf);
close(fd); return ;
}

client

  上面代码需要注意的是,监听程序最大允许接受10个连接请求,如果这十个一直连接不断开的话,后续的连接请求就无法得到处理,所以我们需要在每次请求完毕之后就关闭nfd;下次请求再重新连接;

  第三个程序我们实现基于tcp的聊天程序:

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h> int main()
{
/*创建套接口*/
int fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(fd < ){
perror("socket");
exit(EXIT_FAILURE);
} /*服务端信息*/
struct sockaddr_in srv;
srv.sin_family = AF_INET;
srv.sin_port=htons();
srv.sin_addr.s_addr = htonl(INADDR_ANY); /*绑定*/
int ret = bind(fd,(struct sockaddr *)&srv,sizeof(struct sockaddr ));
if(ret < ){
perror("bind");
exit(EXIT_FAILURE);
}
ret = listen(fd,);
if(ret < ){
perror("bind");
exit(EXIT_FAILURE);
}
struct sockaddr_in snd;
int snd_len = ; /*接受*/
int nfd = accept(fd,(struct sockaddr *)&snd,&snd_len);
if(nfd < ){
perror("accpet");
exit(EXIT_FAILURE);
} char data[] = {};
char revdata[] = {};
/*聊天*/
while(){
memset(revdata, , );
memset(data, , );
ret = recv(nfd,revdata,,);
if(ret < ){
perror("recv");
exit(EXIT_FAILURE);
} printf("client say: %s\n",revdata);
if(strcmp(revdata, "end") == ) {
break;
} ret = read(,data,);
if(ret < ){
perror("read");
exit(EXIT_FAILURE);
}
ret = send(nfd,data,,);
if(ret < ){
perror("recv");
exit(EXIT_FAILURE);
} }
close(nfd);
close(fd);
return ;
}

server

 #include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h> int main()
{
/*创建套接口*/
int sock_fd = ;
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock_fd < ) {
perror("socket");
return ;
}
/*服务端信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons();
ser.sin_addr.s_addr = inet_addr("192.168.1.10"); /*建立链接*/
int ret = connect(sock_fd, (struct sockaddr *)&ser, );
if(ret == -) {
perror("connect");
return ;
} /*聊天*/
unsigned char data[] = {};
unsigned char rec[] = {};
while() {
memset(data, , );
memset(rec, , );
int r_size = read(, data, );
if(r_size < ) {
perror("read");
return ;
} ret = send(sock_fd, data, strlen(data), );
if(ret < ) {
perror("send");
return ;
} ret = recv(sock_fd, rec, , );
if(ret < ) {
perror("recv");
return ;
}
printf("server said: %s\n", rec);
}
close(sock_fd);
return ;
}

client

上面这个代码存在的缺陷是,发送方跟接收只能发送一句接收一句,不能一次性发送多句,要解决这个问题就要需用到IO多路服用,可以通过这个函数来实现:
  int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);

下面贴出代码:

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h> int main()
{
/*创建套接口*/
int fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(fd < ){
perror("socket");
exit(EXIT_FAILURE);
} /*服务端信息*/
struct sockaddr_in srv;
srv.sin_family = AF_INET;
srv.sin_port=htons();
srv.sin_addr.s_addr = htonl(INADDR_ANY); /*绑定*/
int ret = bind(fd,(struct sockaddr *)&srv,sizeof(struct sockaddr ));
if(ret < ){
perror("bind");
exit(EXIT_FAILURE);
}
ret = listen(fd,);
if(ret < ){
perror("bind");
exit(EXIT_FAILURE);
}
struct sockaddr_in snd;
int snd_len = ; /*接受*/
int nfd = accept(fd,(struct sockaddr *)&snd,&snd_len);
if(nfd < ){
perror("accpet");
exit(EXIT_FAILURE);
} fd_set rfds;
char data[] = {};
char revdata[] = {};
/*聊天*/
while(){ FD_ZERO(&rfds);
FD_SET(,&rfds);
FD_SET(nfd,&rfds);
ret = select(nfd+,&rfds,NULL,NULL,NULL);
if(FD_ISSET(nfd, &rfds)){
ret = recv(nfd,revdata,,);
if(ret < ){
perror("recv");
exit(EXIT_FAILURE);
} printf("client say: %s\n",revdata);
if(strcmp(revdata, "end") == ) {
break;
}
}
if(FD_ISSET(, &rfds)) {
ret = read(,data,);
if(ret < ){
perror("read");
exit(EXIT_FAILURE);
}
ret = send(nfd,data,,);
if(ret < ){
perror("recv");
exit(EXIT_FAILURE);
}
}
memset(revdata, , );
memset(data, , );
}
close(nfd);
close(fd);
return ;
}

server

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>int main()
{
/*创建套接口*/
int sock_fd = ;
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock_fd < ) {
perror("socket");
return ;
}
/*服务端信息*/
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons();
ser.sin_addr.s_addr = inet_addr("192.168.1.10"); /*建立链接*/
int ret = connect(sock_fd, (struct sockaddr *)&ser, );
if(ret == -) {
perror("connect");
return ;
} /*聊天*/
fd_set rfds;
unsigned char data[] = {};
unsigned char rec[] = {};
while() {
memset(data, , );
memset(rec, , );
FD_ZERO(&rfds); //清空
FD_SET(,&rfds);//(标准输入)
FD_SET(sock_fd,&rfds);//添加监听描述符(套接字)
/*多路复用IO*/
ret = select(sock_fd+,&rfds,NULL,NULL,NULL); if(FD_ISSET(, &rfds)){//监听键盘是否有输入,执行接收
int r_size = read(, data, );
if(r_size < ) {
perror("read");
return ;
}
ret = send(sock_fd, data, strlen(data), );
if(ret < ) {
perror("send");
return ;
}
} if(FD_ISSET(sock_fd, &rfds)) {//监听sock_fd是否有输入,执行接收
ret = recv(sock_fd, rec, , );
if(ret < ) {
perror("recv");
return ;
}
printf("server said: %s\n", rec);
}
}
close(sock_fd);
return ;
}

client

    

  

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,985
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,501
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,345
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,128
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,763
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,840