Linux Socket 网络编程(一)

Socket 其实是通过在 应用层和 传输层之间 建立一个Socket层的一个中间层,向下可以连接UDP,TCP,当然也可以用作本地进程间通信。

主要包括有
socket(int domain, int type, int protocol);
这里的domain 包含有挺多种的协议族,但我们主要用到两个,AF_UNIX一个是用于UNIX域协议,(文件系统套接字)
另外一个是AF_INET ARPA 因特网协议(UNIX 网络套接字)
type 指的是传输的方式,包括有流 和 数据包(SOCK_STREAM,SOCK_DGRAM),前者借助TCP实现,后者需要UDP实现。就是是否为有链接的服务。
而后者是悬着到底使用什么协议通信,这个一般置零,表示默认通信方式。

套接字有套接字的地址格式。对于 AF_UNIX,和AF_INET 这两者的格式有些不同,注意需要引入不同的库(sys/un.h, netinet/in.h)

struct sockaddr_un{
sa_family sun_family;char sun_path[];
}
sturct sockaddr_in{
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
};
其中
struct in_addr sin addr 结构如下:
struct in_addr{
unsigned long int s_addr;};

注意
1.这里用的是IPv4的地址,如果是IPv6,则会有所不同。
2.还有建议对地址在使用之前首先置零清空,然后再使用,因为在实际编程中,出过一些挺奇怪的情况。

int bind (int socket, const struct sockaddr* address, size_t address_len);
前者是当前该身份 即server/client 的 通过socket函数 获得的一个状态描述
address指的是需要关联的文件系统路径名 或者是IP端口号,
最后的是长度,一般sizeof前面的那个address就好啦。
在client的时候其实可以通过 client_addr.sin_port=htons(0)让系统自动分配一个空闲的端口号。就不需要关联也可以的。

int connect(int socket, const struct sockaddr* address, size_t address_len);
这里的connect参数看起来和bind一模一样,但是注意后两者是你要连接到的目标机的address及其长度。
发起连接的一般为client。

----------------------------下面的一般是作server才会调用的。-----------------------------------------
int listen(int socket, int backlog);
这里的后者是指定套接字队列的最大长度,也就是说允许有多少等待处理的client连接。

int accept(int socket,struct sockaddr* address, size_t address_len);
后两者的是client的address,当然这时候我们是不清楚client的address,不过空设一个参数,把address接回来。

在client 和 server 之间的信息传输 我们可以使用 recv() send()
当然 网络I/O的可以有挺多的函数
  • read()/write()
  • recv()/send()
  • readv()/writev()
  • recvmsg()/sendmsg()
  • recvfrom()/sendto()

提醒:
建议对所有的socket函数的返回值进行判断,这是良好的编程习惯。

下面是实现代码:
------------------------client.c-----------------------------
#include <stdio.h>
#include<sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>

int main(){
int sockfd;
int len;
struct sockaddr_in address,server_address;
char ch='A';

sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
printf("Create Socket Failed.\n");
exit(-1);
}
memset(&address,0,sizeof(address));

address.sin_family=AF_INET;
address.sin_addr.s_addr=htonl(INADDR_ANY);
address.sin_port=htons(0);

bzero(&server_address,sizeof(server_address));
server_address.sin_family=AF_INET;
if(inet_aton("x.x.x.x",&server_address.sin_addr)<=0){//这里的x.x.x.x请填入你要连接的网络ip
printf("Server IP Address Error!\n");
exit(1);
}
server_address.sin_port=htons(5990);//这里的server的端口请注意和服务器相同,并且一般大于1024,另外,可以随意设置,不过如果设置的是网络服务器的话,请留意看看你的云服务器是否打开该端口的访问。

int result=connect(sockfd,(struct sockaddr *)&server_address,sizeof(server_address));
if(result==-1){
perror("oop:client 1");
exit(1);
}
write(sockfd,&ch,1);
read(sockfd,&ch,1);
printf("char from server =%c\n",ch);
close(sockfd);
exit(0);
}

--------------------------server.c ----------------------------------------------

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


int main(){
int server_sockfd,client_sockfd;
int server_len,client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;

server_sockfd=socket(AF_INET,SOCK_STREAM,0);

memset(server_address,0,sizeof(server_address));
server_address.sin_family=AF_INET;
server_address.sin_addr.s_addr=htonl(INADDR_ANY);
server_address.sin_port=htons(5990);
bind(server_sockfd,(struct sockaddr *)&server_address,sizeof(server_address));

listen(server_sockfd,5);
signal(SIGCHLD,SIG_IGN);

while(1){
char ch;
printf("server waitting.\n");

client_len=sizeof(client_address);
client_sockfd=accept(server_sockfd,(struct sockaddr *)&client_address,&client_len);

if(fork()==0){
read(client_sockfd,&ch,1);
sleep(5);
ch++;
write(client_sockfd,&ch,1);
close(client_sockfd);
exit(0);
}
else{
close(client_sockfd);
}
}
}

---------------------------------------------------------------
server:

client:

当然也可以通过server和client进行消息传递。

-----------------------server.c-----------------------

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include <unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>

#define DEFAULT_PORT 5990
#define MAXLINE 4096
int main(int argc, char** argv)
{
int socket_fd, connect_fd;
struct sockaddr_in servaddr;
char buff[4096];
int n;
//初始化Socket
if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
//初始化
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。
servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为DEFAULT_PORT

//将本地地址绑定到所创建的套接字上
if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
//开始监听是否有客户端连接
if( listen(socket_fd, 10) == -1){
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
printf("======waiting for client's request======\n");
while(1){
//阻塞直到有客户端连接,不然多浪费CPU资源。
if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
continue;
}
//接受客户端传过来的数据
n = recv(connect_fd, buff, MAXLINE, 0);
//向客户端发送回应数据
if(!fork()){ /*子进程*/
if(send(connect_fd, "Hello,you are connected!\n", 26,0) == -1)
perror("send error");
close(connect_fd);
exit(0);
}
buff[n] = '\0';
printf("recv msg from client: %s\n", buff);
close(connect_fd);
}
close(socket_fd);
}


-------------------client.c---------------------------

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

#define MAXLINE 4096


int main(int argc, char** argv)
{
int sockfd, n,rec_len;
char recvline[4096], sendline[4096];
char buf[MAXLINE];
struct sockaddr_in servaddr;


if( argc != 2){
printf("usage: ./client <ipaddress>\n");
exit(0);
}


if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
exit(0);
}


memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(5990);
if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
printf("inet_pton error for %s\n",argv[1]);
exit(0);
}


if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}


printf("send msg to server: \n");
fgets(sendline, 4096, stdin);
if( send(sockfd, sendline, strlen(sendline), 0) < 0)
{
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
if((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) {
perror("recv error");
exit(1);
}
buf[rec_len] = '\0';
printf("Received : %s ",buf);
close(sockfd);
exit(0);
}


后续会继续尝试跨系统的socket编程 和文件传输socket编程(毕竟虚拟机之间传输文件太麻烦了)


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值