参考:https://blog.csdn.net/haifengid/article/details/51996613
项目场景:
运行环境:Ubuntu18.04,linux系统,gcc编译器
实现描述:
- 需求:由于目前需要实现网络通信,为后续将串口接收的数据上传做准备,因此需要先打通客户端服务器收发的程序,之后再将其和串口数据接收放在一起,用来实现终端的数据接收线程。
- 解决思路:所以通过对于之前简单实现的网络编程的例子进行查找回顾,进行了实现。通过书籍中的固定章节,因为其存在前后的理论讲解和逻辑分析,所以对其进行了借鉴。
- 问题:直接进行跑例程的时候,想先尝试一下不使用自己的IP直接用例程的IP地址,会出现什么现象,因此就直接按照书籍中所写的IP进行了运行,导致服务器端无法接受客户端发送的请求,一直处于等待状态;
接着更改为自己的IP之后,出现了线程的没有关闭,导致服务器不允许接入运行。
实现过程:
一、首先在Windows环境下编写server1.c以及client1.c,并复制粘贴到linux环境下,进行了编译运行。
1、server1.c
//server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define SERVPORT 3333
#define BACKLOG 10
#define MAX_CONNECTED_NO 10
#define MAXDATASIZE 5
int main()
{
struct sockaddr_in server_sockaddr,client_sockaddr;
int sin_size,recvbytes;
int sockfd,client_fd;
char buf[MAXDATASIZE];
/*建立 socket 连接*/
if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){
perror("socket");
exit(1);
}
printf("socket success!,sockfd=%d\n",sockfd);
/*设置 sockaddr_in 结构体中相关参数*/
server_sockaddr.sin_family=AF_INET;
server_sockaddr.sin_port=htons(SERVPORT);
server_sockaddr.sin_addr.s_addr=INADDR_ANY;
bzero(&(server_sockaddr.sin_zero),8);
/*绑定函数 bind*/
if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct
sockaddr))== -1){
perror("bind");
exit(1);
}
printf("bind success!\n");
/*调用 listen 函数*/
if(listen(sockfd,BACKLOG)== -1){
perror("listen");
exit(1);
}
printf("listening....\n");
/*调用 accept 函数,等待客户端的连接*/
if((client_fd=accept(sockfd,(struct sockaddr *)&client_sockaddr,&sin_size))== -1){
perror("accept");
exit(1);
}
/*调用 recv 函数接收客户端的请求*/
if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){
perror("recv");
exit(1);
}
printf("received a connection :%s\n",buf);
close(sockfd);
}
2、client1.c
/*client.c*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SERVPORT 3333
#define MAXDATASIZE 100
main(int argc,char *argv[]){
int sockfd,sendbytes;
char buf[MAXDATASIZE];
struct hostent *host;
struct sockaddr_in serv_addr;
if(argc < 2){
fprintf(stderr,"Please enter the server's hostname!\n");
exit(1);
}
/*地址解析函数*/
if((host=gethostbyname(argv[1]))==NULL){
perror("gethostbyname");
exit(1);
}
/*创建 socket*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))== -1){
perror("socket");
exit(1);
}
/*设置 sockaddr_in 结构体中相关参数*/
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(SERVPORT);
serv_addr.sin_addr=*((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
/*调用 connect 函数主动发起对服务器端的连接*/
if(connect(sockfd,(struct sockaddr *)&serv_addr,\
sizeof(struct sockaddr))== -1){
perror("connect");
exit(1);
}
/*发送消息给服务器端*/
if((sendbytes=send(sockfd,"hello",5,0))== -1){
perror("send");
exit(1);
}
close(sockfd);
}
3、进行文件拷贝、编译、运行。
注意:
- 因为IP地址输入的是书籍中作者的IP,所以连接不到,需要连接到自己的Ubuntu中的IP。
- 客户端和服务器需要运行在两个终端页面上。(打开两个页面即可);
- 需要先运行服务器端,再运行客户端。
4、然后更改客户端连接IP,重新进行客户端和服务器端连接。
查看Ubuntu自己的IP:
注意:
- 出现了拒绝访问的错误,因为进程被占用。address already in use。
5、搜索原因,并进行杀死对应进程。
参考链接:https://jingyan.baidu.com/article/8ebacdf0c2e35e08f75cd533.html
通过列举出所有的运行线程,自己找到刚刚所执行的程序。
ps -ef
找到对应的线程号为23763,关闭线程即可。
注意:需要使用sudo权限;需要加上-9参数;
sudo kill -9 23763
6、可以看到之前运行的server1进程已经被杀死,可以重新输入自己的IP进行连接了。
结果表明可以成功的实现客户端和服务器端的连接。
简单的记录如上,稍后有其他相关问题会更新的。