socket一些补充

实验过程中先关闭防火墙,避免后续出现不要问题

输入以下命令以停止防火墙服务: sudo systemctl stop iptables
​
输入以下命令以禁用防火墙服务: sudo systemctl disable iptables

实验验收时,应先开启server文件,再开启client文件

server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
//中断错误提示
#define ERR_EXIT(m)     do{ perror(m); exit(EXIT_FAILURE); } while(0)
​
int main()
{
int listenfd;
​
if((listenfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
ERR_EXIT("socket");
​
struct sockaddr_in servaddr;
​
/*memset常用于对第一个参数进行清零,
头文件:C中#include<string.h>,C++中#include<cstring>
参考http://t.csdnimg.cn/R5OR4*/
memset(&servaddr,0,sizeof(servaddr));
​
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(10001);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
​
if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
ERR_EXIT("bind");
​
if((listen(listenfd,SOMAXCONN)) < 0 )//主动套接字,变成被动套接字
ERR_EXIT("listen");
​
struct sockaddr_in peeraddr;
socklen_t socklen = sizeof(peeraddr);
int conn;
if((conn = accept(listenfd,(struct sockaddr*)&peeraddr,&socklen)) < 0)// 获得到是主动套接字
ERR_EXIT("accept");
​
char recvbuf[1024] = {0};//用于接受客户端发送数据
char sendbuf[1024] = {0};//用于存储服务端发送数据
for(;;)
{
    // 从客户端接收数据
    printf("Client: %s\n", recvbuf);
    /*read来源头文件:#include<unistd.h>
    read(int fd,void*buf,size_t count)
    fd:      是文件描述符
    buf:     为读出数据的缓冲区;
    count:   为每次读取的字节数(是请求读取的字节数,读上来的数据
    保存在缓冲区buf中,同时文件的当前读写位置向后移)*/
    read(conn,recvbuf,sizeof(recvbuf));
    /*# include <stdio.h>
    int fputs(const char *s, FILE *stream);
    s 代表要输出的字符串的首地址,可以是字符数组名或字符指针变量名。
    stream 表示向何种流中输出,可以是标准输出流 stdout,也可以是文件流。标准输出流即屏幕输      出,printf 其实也是向标准输出流中输出的。*/
    //与上文printf函数大致相同道理,且由于是获取来自fgets函数,故可以自动换行
    //fputs(recvbuf,stdout);
    
    // 检查退出命令
    if (strcmp(recvbuf, "exit\n") == 0 || strcmp(recvbuf, "quit\n") == 0) {
        printf("Exiting...\n");
        break;
    }
    
    // 服务端输入消息并发送给客户端
    printf("Enter message to client: ");
    //fgets函数与fputs函数对应,是对get函数的封装。通俗理解就是读取字符
    fgets(conn, sizeof(sendbuf), stdin);
    //write和read函数相对应,同理,参考上文。通俗理解为发送字符串
    write(conn,sendbuf,ret);
    
    //接收或者发送完后,清空缓冲区,避免接受或发送残余
    //例如:sendbuf第一回合为123456,sendbuf第二回合为7890
    //则第二回合显示为789056,因为1234被覆盖掉了,但是56没有清空
    memset(sendbuf,0,sizeof(sendbuf));
    memset(recvbuf,0,sizeof(recvbuf));
}
    exit(0);
​
}

client.c

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
​
#define ERR_EXIT(m)      do{  perror(m); exit(EXIT_FAILURE);} while(0)
​
​
int main(int argc,char *argv[])
{
    int sockfd;
    if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
        ERR_EXIT("socket");
    struct sockaddr_in servaddr;
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(10001);
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
​
    if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
        ERR_EXIT("connect");
​
    char sendbuf[1024] = {0};
    char recvbuf[1024] = {0};
​
    while(1)
    {
        // 客户端输入消息并发送给服务端
        printf("Enter message to server: ");
        fgets(sendbuf,sizeof(sendbuf),stdin);
        //也有用send(sockfd, sendbuf, strlen(sendbuf), 0);来等替
        write (sockfd,sendbuf,strlen(sendbuf));
        
        // 检查退出命令
        if (strcmp(sendbuf, "exit\n") == 0 || strcmp(sendbuf, "quit\n") == 0) {
            printf("Exiting...\n");
            break;
        }
        
        // 接收服务器回复
        read(sockfd,recvbuf,sizeof(recvbuf));
        printf("Server: %s\n",recvbuf );
        
        memset(sendbuf,0,sizeof(sendbuf));
        memset(recvbuf,0,sizeof(recvbuf));
    }
    //关闭socket
    close(sockfd);
    exit(0);
​
}
​
​

同时在实验过程中,偶尔会遇到端口被使用,解决办法如下。

Address already in use 端口被占用

//查看当前占用端口命令
netstat -tanlp
​
//或者你知道自己当前被占用的端口号,例如上文中适用的是10001
netstart -apn | grep 10001
​
//2918、3245、3623为pid值,可以再次查询pid来确定是谁启用的端口,避免误杀
ps -ef | grep 2918
​
//杀死进程(注意不是杀死端口,而是pid的端口)
kill 2918 
kill -9 2918(强制删除)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值