网络编程------服务器端与客户端tcp的双向通信
网络编程之实现服务器和客户端的tcp双向通信,前面是双向通信的详细流程介绍,后面附上完整的代码o( ̄▽ ̄)ブ
文章目录
- 网络编程------服务器端与客户端tcp的双向通信
-
- [一、 服务器端](#一、 服务器端)
-
- [1.1 服务器端双向通信的详细流程叙述](#1.1 服务器端双向通信的详细流程叙述)
- [1.2 服务器端双向通信完整代码](#1.2 服务器端双向通信完整代码)
- [二、 客户端](#二、 客户端)
-
- [2.1 客户端双向通信的详细流程](#2.1 客户端双向通信的详细流程)
- [2.2 客户端双向通信完整代码](#2.2 客户端双向通信完整代码)
一、 服务器端
1.1 服务器端双向通信的详细流程叙述
-
创建TCP套接字:
ctcpsock = socket(AF_INET, SOCK_STREAM, 0);
使用
socket
函数创建一个TCP套接字。这里使用了IPv4地址族AF_INET
和流式套接字SOCK_STREAM
。 -
绑定IP和端口:
cret = bind(tcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr));
使用
bind
函数将套接字与指定的IP地址和端口绑定。 -
开始监听:
cret = listen(tcpsock, 5);
使用
listen
函数开始监听客户端的连接请求,设置最大等待连接数为5。 -
接受客户端连接:
cnewsock = accept(tcpsock, (struct sockaddr *)&boyaddr, &addrsize);
使用
accept
函数等待并接受客户端的连接请求。一旦有客户端连接,accept
函数返回一个新的已连接套接字。 -
创建发送消息的子线程:
cpthread_create(&id, NULL, sendmsgtoclient, NULL);
使用
pthread_create
函数创建一个新的线程,该线程的任务是从服务器控制台读取输入,并通过write
函数发送到客户端。 -
接收消息:
cread(newsock, rbuf, 100);
使用
read
函数从已连接套接字中读取客户端发送的消息。 -
关闭套接字:
cclose(tcpsock); close(newsock);
使用
close
函数关闭TCP套接字和已连接套接字,释放资源。
总结:此服务器程序的核心是使用TCP套接字与客户端建立连接,然后创建一个专用的线程来发送消息给客户端。主线程负责接收客户端的消息,并将这些消息打印在服务器控制台上。
1.2 服务器端双向通信完整代码
c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
/*
多线程实现tcp双向通信
服务器的代码
*/
int newsock;
//线程的任务函数--》专门发送信息给客户端
void *sendmsgtoclient(void *arg)
{
char sbuf[100];
while(1)
{
bzero(sbuf,100);
printf("请输入要发送给客户端的信息!\n");
scanf("%s",sbuf);
write(newsock,sbuf,strlen(sbuf));
}
}
int main()
{
int tcpsock;
int ret;
char rbuf[100];
pthread_t id;
//定义ipv4地址体变量存放需要绑定的ip和端口号
struct sockaddr_in bindaddr;
bzero(&bindaddr,sizeof(bindaddr));
bindaddr.sin_family=AF_INET;
bindaddr.sin_addr.s_addr=inet_addr("193.168.1.150"); //女朋友(服务器)自己的ip
bindaddr.sin_port=htons(20000); //女朋友(服务器)的端口号
//定义ipv4地址体变量存放客户端的ip和端口号
struct sockaddr_in boyaddr;
int addrsize=sizeof(boyaddr);
//创建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("绑定ip端口失败了!\n");
return -1;
}
//监听
ret=listen(tcpsock,5);
if(ret==-1)
{
perror("监听失败!\n");
return -1;
}
printf("旧的套接字(监听套接字)是:%d\n",tcpsock);
printf("服务器的代码阻塞在accept位置了!\n");
//接收客户端的连接请求
newsock=accept(tcpsock,(struct sockaddr *)&boyaddr,&addrsize);
if(newsock==-1)
{
perror("接收连接请求失败了!\n");
return -1;
}
printf("有一个客户端连接成功了,产生的新套接字(已连接套接字)是:%d\n",newsock);
//创建一个子线程专门发送信息
pthread_create(&id,NULL,sendmsgtoclient,NULL);
//主线程专门用来接收信息
//循环接收客户端发送过来的内容
while(1)
{
bzero(rbuf,100);
//接收客户端发过来的信息
read(newsock,rbuf,100);
printf("客户端发送过来的内容是:%s\n",rbuf);
}
//关闭套接字
close(tcpsock);
close(newsock);
return 0;
}
二、 客户端
2.1 客户端双向通信的详细流程
-
创建TCP套接字:
ctcpsock = socket(AF_INET, SOCK_STREAM, 0);
使用
socket
函数创建一个TCP套接字。 -
绑定客户端的IP和端口:
cret = bind(tcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr));
使用
bind
函数将套接字与客户端指定的IP地址和端口绑定。 -
连接到服务器:
cret = connect(tcpsock, (struct sockaddr *)&girladdr, sizeof(girladdr));
使用
connect
函数连接到服务器。这里,客户端尝试连接到服务器的IP地址和端口。 -
创建接收消息的子线程:
cpthread_create(&id, NULL, recvmsgfromserver, NULL);
使用
pthread_create
函数创建一个新的线程,该线程专门用于接收从服务器发送过来的消息。 -
主线程发送消息:
cwrite(tcpsock, sbuf, strlen(sbuf));
主线程使用
write
函数发送从键盘输入的消息到服务器。 -
接收消息子线程:
cvoid *recvmsgfromserver(void *arg)
这是一个专用的线程任务函数,其主要工作是从服务器接收消息并在控制台上打印。
-
关闭套接字:
cclose(tcpsock);
使用
close
函数关闭TCP套接字。
总结:此客户端程序的核心功能是创建一个TCP套接字并连接到服务器。一旦连接建立,它会启动一个子线程来接收从服务器发送过来的消息,而主线程则负责从键盘读取输入并将其发送到服务器。
2.2 客户端双向通信完整代码
c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
/*
多线程实现tcp双向通信
客户端的代码
*/
int tcpsock;
//线程的任务函数--》专门接收服务器发送过来的信息
void *recvmsgfromserver(void *arg)
{
char rbuf[100];
while(1)
{
bzero(rbuf,100);
read(tcpsock,rbuf,100);
printf("服务器发过来的信息是:%s\n",rbuf);
}
}
int main()
{
int ret;
char sbuf[100];
pthread_t id;
//定义ipv4地址体变量存放需要绑定的ip和端口号
struct sockaddr_in bindaddr;
bzero(&bindaddr,sizeof(bindaddr));
bindaddr.sin_family=AF_INET;
bindaddr.sin_addr.s_addr=inet_addr("192.168.1.140"); //客户端自己的ip
bindaddr.sin_port=htons(10000); //客户端的端口号
//定义ipv4地址体变量存放女朋友(服务器)的ip和端口号
struct sockaddr_in girladdr;
bzero(&girladdr,sizeof(girladdr));
girladdr.sin_family=AF_INET;
girladdr.sin_addr.s_addr=inet_addr("192.168.1.150"); //服务器的ip
girladdr.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("绑定ip端口失败了!\n");
return -1;
}
//拨号连接服务器
ret=connect(tcpsock,(struct sockaddr *)&girladdr,sizeof(girladdr));
if(ret==-1)
{
perror("连接失败了!\n");
return -1;
}
//创建一个子线程用来接收信息
pthread_create(&id,NULL,recvmsgfromserver,NULL);
//主线程用来发送信息
//循环从键盘输入内容发送给服务器
while(1)
{
bzero(sbuf,100);
printf("请输入要发送给服务器的信息!\n");
scanf("%s",sbuf);
//发送给服务器
write(tcpsock,sbuf,strlen(sbuf));
}
//关闭套接字
close(tcpsock);
return 0;
}